为什么要了解GC
对于Java程序猿来说,内存分配与释放都交给JVM处理,而更多的精力能够投入到业务开发中去,这也是Java能够受广大开发者欢迎的重要原因之一。但问题来了,万一程序出现内存泄漏和内存溢出问题怎么排查,如何定位问题,所以防患于未然,了解JVM的GC原理是每位Java开发者的职业素养。
对象实例收集算法
1.引用计数算法
顾名思义,就是为对象添加一个引用计数,用于记录对象被引用的次数,对象引用计算为0,则表示对象可回收。Java并没有选择引用计数机制,因为它不可解决循环引用的问题。
2.可达性分析
Java选择的是可达性分析算法。其原理是将对象及其引用看作一个关系图,选定对象作为GC Roots,然后跟踪引用链条,如果一个对象和GC Roots之间不可达,也就是说不存在引用链条,那么即可认为是可回收对象。JVM会把虚拟机栈和本地方法栈中引用的对象、静态属性引用的对象和常量,作为GC Roots。
如图,GC Roots作为实例对象,obj1、obj2、obj3、obj4与GC Roots存在引用链条,而obj5、obj6、obj7与GC Roots不存在引用链条,呢么obj5、obj6、obj7则被视为可回收对象。
GC算法
1.标记清除算法(Mark-Swap)
分为两个阶段:标记和清除。标记阶段的工作是标记可回收对象的内存。清除阶段的工作是清除已标记的内存。
优点:效率高。
缺点:多次清除后,会产生大量的内存碎片
2.复制算法(Copying)
按内存容量分为两部分:已使用和未使用。把已使用部分的存活对象复制到未使用部分,统一回收已使用部分的全部空间,那么就不会出现Mark-Swap算法的内存碎片问题。
优点:效率高、保持内存的最大可用性。
缺点:当存活数量较多的时候,效率会骤降。
3.标记整理算法(Mark-Compact)
分为两个阶段:标记和整理。标记阶段和Mark-Swap阶段一样。整理阶段工作是把存活对象移向一端,统一处理可回收内存,解决了Copying算法和Mark-Compact算法的结构弊端。
优点:保持内存的最大可用性。
缺点:效率低。
垃圾收集器
1. 比较应用
收集器 | 作用年代 | 线程状态 | 算法 | 特点 | 场景 |
---|---|---|---|---|---|
Serial | 新生代 | 串行 | 复制 | 响应速度优先 | 单CPU环境下的Client模式 |
ParNew | 新生代 | 并行 | 复制 | 响应速度优先 | 多CPU环境Server模式下与CMS配合使用 |
Parallel Scavenge | 新生代 | 并行 | 复制 | 吞吐量优先 | 适用于后台运算而且不需要太多交互的场景 |
Serial Old | 老年代 | 串行 | 标记-整理 | 响应速度优先 | 单CPU环境下的Client模式 |
Parallel Old | 老年代 | 并行 | 标记-整理 | 吞吐量优先 | 适用于后台运算而不需要太多交互的场景 |
CMS | 老年代 | 并行 | 标记-清除 | 响应速度优先 | 适用于互联网或者B/S业务 |
G1 | 新生代/老年代 | 并行 | 标记-整理算法+复制算法 | 响应速度优先 | 面向服务器端应用 |
ZGC | 不分代Region | 并发 | 着色指针 +读屏障 +压缩整理 |
处理大堆 | 面向服务器端应用 |
2. 分代关系与实用
新生代 | 老年代 | JVM参数 |
---|---|---|
Serial | Serial Old | -XX:+UseSerialGC |
Parallel Scavenge | Serial Old | -XX:+UseParallelGC |
Parallel Scavenge | Parallel Old | -XX:+UseParallelOldGC |
ParNew | Serial Old | -XX:-UseParNewGC |
ParNew | CMS+Serial Old | -XX:+UseConcMarkSweepGC |
G1 | G1 | -XX:+UseG1GC |
注:
Java8新生代默认Parallel Scavenge,老年代默认Parallel Old
Java9默认是G1
3. CMS
- 初始标记:标记Root直接可达对象,会STW。
- 并发标记:标记所有可达对象。
- 重信标记:二次标记,时间比并发时间短,但比初始标记时间长,会SWT。
- 并发清理:清理已经死亡的对象。
- 并发重置:为下次GC重置数据结构。
4. G1
没有物理化的年代区分,都是对象都是一个个Region,保持高回收率减少停顿,是逻辑分代管理,分为年轻代、老年代、矩形对象。G1会全局扫描。
- 年轻代:使用并行复制算法清除对象。
- 老年代:使用标记整理方法清除对象,由于不是全局清除,是局部清除所以STW的时间短。
- 初始标记(SWT):同CMS
- 并发标记:同CMS
- 最终标记(SWT):同CMS
- 复制/清除(SWT):优先回收可回收空间较大的Region(G garbage First),每次只清理一部分,而不是全局清理。
5. ZGC
特点:能做到10ms以下的回收停顿时间,支持TB级别的对象回收。
过程:划分许多大小不一的Region,然后通过短暂的SWT标记Roots对象,并发通过着色指针的标记可回收对象(边缘情况可能SWT),并发清除后进行并发重定位。
- 着色指针:在64位OS中,最大支持4TB的堆占用42位,剩下22位可用作其他用途,目前只使用了4位着色指针标记。
- 读屏障:为了解决用户线程和GC线程并发导致对象状态的问题,减少SWT。
- 并发执行:由于读屏障的支持,大部分之间都是并发执行的。
- 基于Region:没有固定大小的Region,所以对象大小可支持TB,等大堆内存。
- 压缩整理:对象回收后会整理压缩内存空间,防止内存碎片问题。