JVM笔记汇总

由 Geooo 发布于 February 14, 2022

Java虚拟机

内存模型

img

  • 堆(Heap):线程共享,所有的对象实例以及数组都要在堆上分配,回收期主要管理和清理的内存空间。
  • 方法区(Method Area):线程共享,存储已被虚拟机加载的类信息静态变量常量即时编译器后的代码运行时常量池
  • Java虚拟机栈(JVM Stack):线程私有,存储局部变量表、操作数栈、动态链接、方法出口,对象指针。
  • 本地方法栈(Native Method Stack):线程私有,主要用于虚拟机使用到的Native方法。(比如Java使用C或者C++编写的接口服务时,代码在此区域运行)。
  • 程序计数器(Program Counter Register):线程私有,记录当前线程执行的字节码的行号指示器,指向下一条要运行的指令。

JDK8之前HotSpot JVM是使用永久代去实现方法区,永久代是一个连续的堆空间。在JDK8以后,HotSpot JVM使用元空间(Meta Space)实现方法区,类的元信息(metadata)还在,只不过不再是存储在连续的对空间上,而是存储在元空间的本地内存(Native Memory)

动态链接 : 被调用的目标方法再编译期无法被确认,只有在程序运行期间将方法的符号引用转换为直接引用,这种引用转换的过程具备动态性,称为动态链接

方法的绑定机制分为前期绑定后期绑定

堆主要存放 对象实例数组,而从结构上来说,堆可以分为新生代老年代新生代里分为 Eden区,From Survivor (S0)To Survivor (S1)

所有新生成的对象首先都省分配存放在 新生代,需要注意的是,两个Survivor区是对称的,没有先后关系,所以同一个区有可能存在从Eden区复制过来的对象,和从前一个 Survivor区复制过来的存活对象。而复制到老年代的对象只可能是从第一个Survivor区中复制过来的对象。

新生代(Young Gen)

Eden区

新生成(new)的对象都是存放在 Eden 区,当 Eden区 空间不足时,JVM会出发一次 Minor GC (Young GC),此时垃圾回收器会扫描Eden区和From区存活下来的对象,大部分对象会被回收(朝生夕死),存活下来的对象会被复制到Survivor To区中,年龄达到的对象会被直接复制到老年代 (Old Gen)

Survivor区

From SurvivorTo Survivor 组成,Survivor区相当于是 Eden区 和 Old Gen的缓冲区,如果没有Survivor区的话,Old Gen(老年代)很快被填满,然后触发 Major GC, 因为 Major GC(Full GC)一般都伴随着Minor GC, Survivor区存在的意义就是减少对象进入老年代,从而减少Major GC(Full GC)的频率。

Survivor又分为 From区To区。JVM每次执行Minor GC的时候,都会将 Eden区Survivor From (S0) 存活下来的对象复制到 Survivor To区(当To区内存不足的时候,直接进入Old区),并且对对象的年龄值+1,到达一定年龄(年龄 > 15),会晋升到老年代。

15岁这个年龄可以通过虚拟机参数进行配置 -XX:MaxTenuringThreshold ,晋升老年代还有个 动态年龄

Hotspot遍历所有对象时,按照年龄从小到大对其所占用的大小进行累积,当累积的 某个年龄大小超过了survivor区的 TargetSurvivorRatio(一般是0.5 一半) 时,取这个年龄和MaxTenuringThreshold 中更小的一个值,作为新的晋升年龄阈值

老年代