【深入理解JVM】常见的垃圾回收器
分类
- 按线程数分,分为串行垃圾回收器和并行垃圾回收器
- 按工作模式分,分为独占式垃圾回收和并发式垃圾回收
- 按碎片处理方式分,分为压缩式垃圾回收器和非压缩式垃圾回收器:
- 区别在于是否对存活对象进行整理,消除回收后的碎片
- 按工作的内存区间分,分为年轻代垃圾回收器和老年代垃圾回收器
评估GC的性能指标
吞吐量:运行用户代码的时间占总运行时间的比例
快速:一个对象从诞生到被回收所经历的时间
查看默认的垃圾收集器
-XX:+PrintCommandLineFlags
Serial回收器
- 串行回收
- 复制算法+串行回收+STW
- 在老年代Serial Old 标记-压缩+串行回收+STW
- 使用一个收集线程完成垃圾收集工作,收集时必须暂停其他所有的工作线程
- 对于限定单个CPU单核心环境效率更高
- -XX:+UseSerialGC
ParNew回收器
- 并行回收
- 复制算法+并行回收+STW
- 对于新生代,回收次数频繁,可以使用并行方式
- 对于老年代,回收次数少,使用串行方式节省资源
- 多核心环境
- -XX:+UseParNewGC -XX:ParallelGCThreads限制线程数量,默认开启和CPU数据相同的线程数
Parallel回收器
- 吞吐量优先
- 并行回收
- 复制算法+并行回收+STW
- ParalleelOld 标记-压缩+并行回收+STW
- 目标是达到一个可控制的吞吐量(Throughput)
- 自适应调节策略
- 适合在后台运算而不需要太多交互的任务
- -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:ParallelGCThreads
- -XX:MaxGCPauseMillis垃圾收集器STW最大时间 -XX:GCTimeRatio垃圾时间占总时间的比例(0,100)默认99即垃圾回收时间不超过1%
- -XX:+UseAdaptiveSizePolicy自适应调节策略
- 在这种模式下,年轻代、Eden和Survivor的比例、晋升老年代的对象年龄等参数会被自动调节
CMS回收器
- 低延迟
- 垃圾收集线程与用户线程同时工作,并发收集
- 标记-清除算法+STW
- 注重响应速度的业务
- 作为老年代回收器,无法与Parallel配合
- 初始标记:STW,标记处GCRoots能直接关联到的对象
- 并发标记:从GCRoots的直接关联对象开始遍历整个对象图
- 重新标记:STW,修正并发标记期间产生变动的那一部分标记的对象的标记记录
- 并发清除:清理删除掉标记节点判断的已经死亡的对象,并释放内存空间
- 不能是内存满了再回收,而是堆内存到达一定阈值后再回收。若预留的空间不足,就会出现“Concurrent Mode Failure”,临时启用Serial Old收集器
弊端:
- 产生内存碎片/使用户可用空间不足,在无法分配大对象的情况下,提前触发FullGC
- 对CPU资源很敏感。并发阶段会占用一部分线程导致应用程序变慢,总吞吐量会降低
- 无法处理浮动垃圾。在并发标记阶段如果产生新的垃圾对象,CMS无法对这些垃圾对象进行标记,导致垃圾对象没有被及时回收
- 参数:
- -XX:+UseConcMarkSweepGC -XX:CMSlnitiatingOccupanyFraction设置阈值。
G1回收器
- 并行回收器
- 把堆内存分成不相关的区域(Region)。使用不同的Region来表示Eden,Servivor,老年代。采用分区算法
- 有计划的避免在整个Java堆中进行全区域的垃圾收集
- 每次根据允许的收集时间,优先回收价值最大的Region
- 针对配备多核CPU及大容量内存的机器
- 优势:
- 并行性与并发性
- 分代收集
- 空间整合。Region内部是复制算法。整体可以看作标记-压缩
- 可预测的停顿时间模型:每次根据允许的收集时间,优先回收价值最大的Region
- 参数:
- -XX:+UseG1GC
- -XX:G1HeapRegionSize设置每个Region大小。值是2的幂
- -XX:MaxGCPauseMillis期望达到的最大GC停顿时间指标
- -XX:ParallelGCThread设置工作线程数
- -XX:ConcGCThreads并发标记的线程数。设置为并行垃圾回收线程数的1/4
- -XX:InitiatingHeapOccupancyPercent并发GC周期的Java堆占用率阈值
- 适用场景:
- 面向服务端,具有大内存多处理器
- 低GC延迟
Remembered Set
使用RSET来避免全局扫描,每个Region都有对应的RSET
每次Reference类型数据写操作时,先进行写屏障(Write Barrier)暂时中断操作。检查写入的引用指向的对象是否和该Reference类型数据在不同的Region,如果不同,通过CardTable把引用信息记录到RSET中
进行垃圾收集器,GC根节点的枚举范围加上RSET,保证不会进行全局扫描
GC日志
参数:
- -XX:+PrintGC
- -XX:+PrintGCDetails详细日志
- -XX:+PrintGCTImeStamps输出GC的时间戳 以基准时间的形式
- -XX:+PrintGCDateStamps输出GC的时间戳 以日期形式
- -XX:+PrintHeapAtGC在进行GC的前后打印出堆的信息
- -Xloggc:../logs/gc.log日志文件输出路径