一、Java及JVM简介

1.1 如何看待框架

大部分Java开发人员,除了会在项目中使用到与Java平台相关的各种高精尖技术框架,对于Java技术的核心——Java虚拟机了解甚少。
一些有一定工作经验的开发人员,打心眼里觉得SSM、微服务等上层技术才是重点,基础技术并不重要,这其实是一种本末倒置的病态。
image
计算机系统体系对我们来说越来越远,在不了解底层实现方式的前提下,通过高级语言很容易编写程序代码,但事实上计算机并不认识高级语言。
image.png

1.2 为什么要学习JVM

  1. 面试的需要
  2. 中高级程序员必备技能,项目管理、调优的需要
  3. 追求极客的精神,垃圾回收算法、JIT(Just In Time)、底层原理

垃圾收集机制为我们打理了很多繁琐的工作,大大提高了并发的效率。但是垃圾收集也不是万能的,懂得JVM内部的内存结构、工作机制,是设计拓展性应用和诊断运行时问题的基础,也是Java工程师进阶 的必备能力。

1.3 Java生态圈

Java是目前应用最为广泛的软件开发平台之一。随着Java及Java社区的不断壮大,Java早已不是一门简单的计算机语言,而成为了一个平台、一种文化、一个社区。

  1. 作为一个平台,JVM扮演着举足轻重的作用,Groovy、Scala、JRuby、Kotlin都是基于JVM的。
  2. 作为一种文化,Java几乎成了开源的代名词,不仅有Tomcat、Mybatis、Spring等Java优秀框架,连JDK和JVM自身都有开源实现,如OpenJDK、Harmony。
  3. 作为一个社区,Java拥有全世界UI多的技术拥护者和开源社区支持。

1.4 JVM:跨语言的平台

image.png
write once, run anywhere. 一次编写,到处运行。
compile once, error everywhere. 一次编译,到处报错。
image.png
Java不是最强大的语言,但JVM是最强大的虚拟机,JVM是一个比Java更成功的作品。

随着Java7的发布,JSR-292规范实现了在JVM上运行非Java语言编写的程序。

Java虚拟机不关心运行在内部的程序到底是何种语言编写的,它只关心字节码文件,只要其他编程语言的编译结果满足并包含Java虚拟机的内部指令集、符号表以及其他辅助信息,就是一个有效的字节码文件,JVM就能识别并装载运行。

Java平台上的多语言混合编程正成为主流,各种语言间的交互不存在任何困难,就像使用自己语言的原生API一样方便,因为他们都运行在一个虚拟机之上。

二、Java发展的重大事件

image.png
image.png

在JDK11之前,Oracle JDK中还会存在一些Open JDK没有的,闭源的功能,但是在JDK11中,OpenJDK和OracleJDK代码实质上已经完全一致,只是协议不同。

三、虚拟机与Java虚拟机

3.1 什么是虚拟机

所谓虚拟机,就是一台虚拟的计算机,是一个软件,用来执行一系列虚拟计算机指令。
大体上分为系统虚拟机(Visual Box/VMware)和程序虚拟机(JVM),在虚拟机上运行的软件都被限制余虚拟机提供的资源。

分类
  1. 系统虚拟机完全是对物理计算机的仿真,提供了一个可运行操作系统的软件平台。
  2. 程序虚拟机专为执行单个计算机程序而设计,在JVM中执行的指令我们称为Java字节码指令,Java字节码未必由Java语言编译。

3.2 Java虚拟机

Java的核心技术就是JVM,因为所有的Java程序都运行在JVM上。
JVM平台的各种语言可以共享JVM带来的跨平台性、优秀的垃圾回收机器以及可靠的及时编译器。

作用

Java虚拟机就是二进制字节码的运行环境,负责装在字节码到其内部,解释/编译为对应平台上的机器指令执行。
每一条Java指令,Java虚拟机规范中都有详细定义,如怎么取操作数,怎么处理操作数,处理结果放哪里。

特点
  1. 一次编译,到处运行。
  2. 自动内存管理。
  3. 自动垃圾回收功能。

四、JVM的整体结构

4.1 JVM的位置

image.png

4.2 JVM的整体结构

image.png
多线程共享方法区和堆,每个线程单独维护一份Java栈、本地方法栈、程序计数器。
详细版
image.png

五、Java代码执行流程

image.png
image.png
JIT编译器会对热点代码进行二次编译,直接编译成机器指令并缓存。

六、JVM的架构模型

Java编译器输入的指令流基本上是一种基于栈的指令集架构,另一种指令集架构是基于寄存器的指令架构。

6.1 基于栈式架构的特点

  1. 设计和实现更简单,适用于资源受限的系统。
  2. 避开了寄存器的分配难题,直接在栈顶操作,使用零地址指令方式进行分配。
  3. 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈。指令集更小,编译器更容易实现。
  4. 不需要硬件支持,可移植性更好,更好实现跨平台。

6.2 基于寄存器架构的特点

  1. 指令集架构完全依赖硬件,可移植性差。
  2. 直接用cpu在高速缓存区高效执行,性能优秀。
  3. 花费更少的指令去完成一项操作。
  4. 指令集一般以一地址指令、二地址指令、三地址指令为主。
  5. 典型的应用是X86的二进制指令集,比如PC和Android和Davlik虚拟机。

6.3 class文件反编译

StackStrTest.java

public class StackStrTest {
    public StackStrTest() {
    }

    public static void main(String[] args) {
        int i=2;
        int j=3;
        int k = i+j;
    }
}

在StackStrTest.class目录下执行反编译命令

javap -v StackStrTest.class

输出结果

public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: iconst_2
         1: istore_1
         2: iconst_3
         3: istore_2
         4: iload_1
         5: iload_2
         6: iadd
         7: istore_3
         8: return

6.4 总结

由于跨平台的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。
栈架构的优点是跨平台,指令集小,编译器容易实现。
缺点是性能下降,实现同样功能需要更多的指令。

七、JVM的生命周期

7.1 虚拟机启动

JVM的启动时通过引导类加载器(bootstarp class loader)创建一个初始类(initial class)来完成的,这个类是有虚拟机的具体实现指定的。

7.2 虚拟机执行

一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序。
程序开始执行时JVM就运行,程序结束时JVM就停止。
执行一个所谓的Java程序的时候,真真正正在执行的是一个叫做Java虚拟机的进程。

public class StackStrTest {
    public static void main(String[] args) {
        int i=2;
        int j=3;
        int k = i+j;

        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("down!");
    }
}

在命令行执行Jps,查看当前运行的Java进程

13908 Launcher
32324
41444 Jps
34280 StackStrTest
32236 KotlinCompileDaemon

7.3 虚拟机退出

  1. 正常执行结束。
  2. 程序在执行过程中遇到了异常或错误而异常终止。
  3. 由于操作系统出现而Java虚拟机进程终止。
  4. 某线程调用Runtime类或System类的exit/halt方法,并且Java安全管理器也允许这次操作。

八、JVM的发展历程

历史JVM

image.png
image.png

三大主流JVM

image.png
image.png
image.png

两款专用JVM

image.png
image.png

国内JVM

image.png

安卓虚拟机

image.png

展望

image.png

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议