JVM 全称是 Java Virtual Machine ,即Java虚拟机
1.JVM 的体系结构
-
字节码指令集 (由执行引擎负责执行)
-
执行引擎(类似于计算机的CPU)
- 垃圾回收 (GC,Garbage Collection)
- 即时编译器
-
内存区
- 一组寄存器
- 一个栈
- 堆
- 储存方法域(包括方法区和本地方法区)
JVM 运行过程
Java 源文件 -> Javac 编译器 -> .Class 字节码文件 -> JVM -> 机器码
在这个过程中,.class 文件是通过类加载器加载到 JVM 中的。
Hotspot JVM 在后台运行的系统线程主要有:
- 虚拟机线程
- 周期性任务线程(负责定时器事件)
- GC线程(负责垃圾回收)
- 编译器线程(将字节码编译为机器码)
- 信号分发线程
2.字节码指令集
JVM 的指令集和 OS 中学到的RISC和CISC类似,是能被JVM 解析执行的一套符合class文件规范的字节码指令集。
3.执行引擎
不同公司的执行引擎有不同的设计,例如 sun 公司的 hotspot 是基于栈的执行引擎,而 Google 的 Dalvik 是基于寄存器的执行引擎。
这两种设计有着各自的优劣。
比如在运算的时候,假设JVM要进行一个加法的运算:
- 如果是基于栈的设计,我们需要先将两个操作数入栈,然后再弹出这两个数进行加法运算,最后将运算的结果入栈;
- 而基于寄存器的设计,我们只需要将两个操作数放入两个寄存器中,然后进行运算并将结果存入其中一个寄存器就可以了。
可以看到,基于寄存器的设计有着更少的数据移动的操作。但是不同的平台上的机器的寄存器可能有着十分大的差别,有的机器寄存器数量很少,有的机器寄存器没有规律,难以设计。因此基于栈的设计有着更好的跨平台移植性。而Google 的 Dalvik 是设计于安卓平台上特定芯片(ARM)的,牺牲了可移植性但是考虑了更多性能。
4.JVM 内存
-
线程私有区域
- 程序计数器
- 栈
- 本地方法区
-
线程共享区
- 堆
- 方法区
A.程序计数器
Program Counter,简称PC,本质上是一个寄存器。它保存了当前执行的程序的地址,
多个线程同时执行的时候,该线程能够在被中断前知道当前执行的地址并保存下来,到重新切回该线程的时候,能够继续将程序执行下去。
补充:java方法的地址会计数器记录,但是本地方法不会。
B.栈
该线程执行方法所需要的空间。每个方法在被调用的时候就会创建一个栈帧(Frame),在结束运行的时候栈帧会弹出一个元素作为方法的返回值,然后这个站帧就会被清除。Java栈的栈顶的栈帧就是当前正在执行的方法。
栈帧中保存了以下几个元素:
- 方法中定义的局部变量(如果局部变量是基本类型,就保存在栈里,如果是对象,只在栈中保存引用,对象保存在堆中)
- 操作栈
- 返回地址
…
C.本地方法区
为本地方法服务,作用类似栈。
D.堆
存放Java对象,堆是线程共享的,里面的对象可以进一步分为新生代和老年代。
E.方法区
存放类的结构信息,类的常量,静态变量,构造函数,方法等都会存放在这里。
.class文件经过 JVM 解析后的这些部分数据就是存放在这里的。这里也叫永久代,垃圾回收器同样会对其进行管理,但永久代不会频繁地被回收。这个区域也是线程共享的