我们常说的JVM一般指的Sun的HotSpot VM,其具备热点探测功能,可将一个被频繁调用的方法或代码块标记为“热点代码”,然后通过内置的JIT(Just In Time Compiler)编译为本地机器指令。
除了HotSpot,市面上还有IBM J9VM,各大linux发行版预装的openjdk等,Java在中国最大的用户淘宝有基于openjdk深度定制的TaobaoVM,改写了大量的HotSpot源码,详见:AliJVM。
JVM运行时数据区
- 栈
栈帧,保存局部变量表、操作数栈等。 - 本地方法栈
- PC寄存器
- 堆
存储对象,自动GC;分为新生代(eden区、s0/from区、s1/to区,from/to又叫survivor区)、老年代(tenured)。(关于Java堆内存分代概述) - 方法区
存储类信息(常量池、字段描述、方法描述等),jdk1.6/1.7也叫永久代,JDK1.8为元数据区,是堆外的直接内存 - 直接内存
注意随着JVM技术的发展,对象未必就一定分配在堆上,基于逃逸分析技术的栈上分配就会把对象放在栈里。
垃圾判别算法
- 引用计数:存在循环引用问题。
- 可达性分析:是否在GC root的引用链中。找到所有的GC的根结点(GC Root), 将他们放到队列里,然后依次递归地遍历所有的根结点以及引用的所有子节点和子子节点,将所有被遍历到的结点标记成live。
GC root包括:
- 虚拟机栈引用的对象
- 方法区静态属性引用的对象
- 方法区常量引用的对象
- 本地方法栈引用的对象方法
引用级别:
- 强引用:不回收
- 软引用:空间不足时回收
- 弱引用:发现即回收
- 虚引用:对象回收跟踪
垃圾回收算法
分代垃圾回收(Generational Collecting)
新生代、老年代。
分代垃圾回收的一大优点是不同分代可依据其特性使用最适合的垃圾收集算法。
卡表数据结构加速新生代的回收。
- 标记清除(Mark-Sweep):会造成内存空间不连续;
- 复制(Coping):内存空间一分为二(具体根据实际情况,Java新生代中eden:s0:s1默认为8:1:1),回收后内存无碎片,在新生代串行垃圾回收器中有应用;
- 标记整理(Mark-Compact):不会产生内存碎片,也不需要两块相同的空间,在老年代的回收。
- 分区算法(Region):G1回收器采用该思想。