1. JVM的内存模型
JVM = 类加载器 + 运行时数据区 + 执行引擎
- 方法区,堆,执行引擎,本地库接口为线程共享。
- 虚拟机栈,本地方法栈,程序计数器为线程独占。
1.1 各个区域的作用
1. 线程私有
- 程序计数器 : 当前线程所执行的字节码的行号指示器。如果线程执行一个Java方法,计数器记录的是正在执行的虚拟机字节码指令的地址。若是native方法,这个计数器值则为空。
- 虚拟机栈:存放的是一系列栈帧。栈帧中包括局部变量表,操作数栈,动态链接。
- 本地方法栈:存放Native方法的栈帧。
2. 线程共享
- 方法区。 用于存储已被虚拟机加载的类信息、变量、静态变量、即时编译器编译后的代码。
- 运行时常量池, 是方法区的一部分,用于存储字面量和符号引用。
- 堆:存放对象实例。
GC 主要针对Java堆
合理的内存模型可以使GC的性能更加强大。不必太大的浪费服务器的性能。从而减少阻塞带来的程序的性能的影响。
2. 两大核心点
2.1 年轻代
- 伊甸园区
- 存活区
- $0
- $1
- 伸缩区
2.2 老年代
- 旧生代
- 伸缩区
3. GC处理流程
- 对象的实例化需要根据关键字new完成,所有的新对象,都会在伊甸园开辟,如果伊甸园换的内存空间不足会发生MinorGC
- 伊甸园不是无限大,所以肯定有些对象执行了N次的MinorGC后还会存在,那么这些对象会进入到存活区。存活区有两个,一个负责保存存活对象,一个负责晋升。永远有一个空内存。
- 若果进行过若干次的MinorGC回收处理后,依然不够使用,那么进行老年代的GC回收。执行了一个MajorGC(Full GC 性能很差)如果可以回收空间,则继续进行MinorGC
- 若果MajorGC失败,则继续内存已经占用充满,则抛出OOM异常。
- 如果新创建的对象的空间占用过大,进入老年代。
- JDK1.8 会根据系统的不同选择不同的GC回收策略
- JDK1.9 - 1.11 默认使用G1回收
4. 内存回收算法
年轻代回收算法
- 复制清理算法 将保留的对象复制到存活区之中,存活区的内容会保存到老年代之中
- 伊甸园区总会产生大量的新对象。所以HotSpot虚拟机使用了BTP(单一CPU时代所有的对象依次保存) TLAB 形式进行处理(拆分成把成的不同的块,依据CPU的核心个数拆分)。
老年代回收算法
- 标记清除算法
- 一次标记暂停程序的执行
- 串行标记
- 并行标记
- 标记压缩
- 将零散的内容进行整理,重新集合再分配。
- 一次标记暂停程序的执行
年轻代 串行GC
年轻代 串行回收GC
年轻代 并行GC
老年代 串行GC
老年代 并行GC
老年代 CMS
STW设计问题。GC回收的时候,需要停止当前的程序。进行无用的对象的标记。
没有任何一项合适的GC回收操作。从JDK1.8 开始提供G1收集器,在JDK11 之后 有了ZGC
4. G1
支持大内存 支持 4g以上 4- 64
支持多CPU
减少STW问题
保证并发状态下程序的执行。