最近朋友小B说想一份GC优化的资料内容,JVM内存分析以及性能调优的时候方便查询。可是文章太多根本看不过来,那么今天指北君就为大家带来这份,GC垃圾收集器总结及其优化指南,让你的JVM从此不再寂寞。文末更有惊喜。
1 垃圾收集器
1.1 Serial/Serial Old 收集器:
Serial 收集器作用于年轻代中, 采用 复制算法 , 属于串行回收方式
Serial Old 收集器 采用串行回收, STW机制, 采用 标记-压缩 算法 ,
"-XX:+UseSerialGC" 手动指定Serial收集器执行内存回收任务
“-XX:+PrintGCDetails” 年轻代串行收集器的工作日志开关
1.2 ParNew 收集器
ParnNew 可以说是Serial收集器的多线程版本, ParNew 收集器在 年轻代 中同样才用的也是复制算法 和 STW 机制 并行回收机制。
ParnNew 收集器的优势体现在多CPU,多核心的环境中, 在某些注重低延迟的应用场景下ParNew 和 CMS 收集器的组合模式, 在Server 模式下的内存回收效果很好。
使用 “-XX:+UserParNewGC” 手动指定使用ParNew收集器 "
-XX:+UserParallelGC" 表示 年轻代使用并行垃圾回收器, 老年代使用串行收集器
1.3 Parallel/Parallel Old 收集器
Parallel收集器是并行回收 采用复制算法 年轻代 STW , 和ParNew不同Parrllel收集器可以控制程序的吞吐量大小 , 被称为-吞吐量优先的垃圾收集器.
Parallel Old采用标记整理算法,用于老年代的垃圾回收。
常用参数:
“-XX:+GCTimeRatio:N” 设置执行内存回收的时间所占JVM运行总时间的比例, 1/(1+N) 默认N为99
“-XX:+MaxGCPauseMills” 设置执行内存回收STW 的暂停时间阈值, 若指定该值,则尽可能地在设定的时间内完成内存回收。
“-XX:+UseAdaptiveSizePolicy” 选项用于设置GC的自动分代大小调节策略。
"-XX:UseParallelOldGC"可在年轻代和老年代都是用并行回收收集器, 此收集器重点关注吞吐量
“-XX:ParallelGCThreads” 可用于设置垃圾回收时的线程数量
Parallel Old 收集器采用了 标记-压缩算法 , 用于老年代垃圾回收 , 并行回收 STW
Parallel 和 Parallel Old 收集器的组合 在Server 模式下的内存回收性能较好。
1.4 CMS(Concurrent-Mark-Sweep) 收集器
基于低延迟的考虑 , 是并行垃圾回收器, 而且是老年代垃圾收集, 低延迟, 采用标记清除算法。会有短暂的STW
基本步骤如下 :
1. 初始标记(Initial Mark) : STW 标记根对象直接关联、可达的对象
2. 并发标记(Concurrent Mark) :将不可达对象 标记为垃圾对象
3. 再次标记(Remark) : STW 确保垃圾对象被成功且正确得标记
4. 并发清除(Concurrent Sweep): 垃圾回收
常用参数:
“-XX:+UseCMS-CompactAtFullCollection” 用于指定在执行完FullGC 之后 是否对内存空间进行压缩整理,
“-XX:+CMSFullGCs-BeforeCompaction” 设定在执行多少次FullGC 之后对内存空间进行压缩整理
“-XX:+CMSInitiatingOccupanyFraction” 设置老年代中的内存使用率达到多少百分比的时候执行内存回收 JDK1.6之前默认值为68% JDK1.6 之后默认92% , CMS垃圾收集器在回收过程中程依然可能会产生垃圾,所以需要设定一个阈值来进行垃圾回收,如果CMS回收失败,JVM则会启动老年代串行收集器进行垃圾回收,程序的STW时间会较长, 所以可以在内存增长缓慢的程序里面设置较大阈值,在内存增长快速的程序里面设置较小的阈值, 避免触发老年代串行收集器。
“-XX:UseConMarkSweepGC” 表示年轻代使用并行收集器,老年代使用CMS 年轻代 并行收集器工作时的线程数量可以使用 “-XX:ParallelGCThreads” 选项指定, 一般最好与CPU的数量相当.
1.5 G1(Garbage-First) 收集器
G1将整个堆划分为若干个大小相等的区间(1-32MB),Region类型分为Unused Region、Eden Region 和 Survivor Region组成了年轻代空间,Old Region, Humongous Region(里面的对象超过每个Region的50%),
每个Region都会有一个Region Set (RS),RS的数据结构是Hash表,里面的数据是CardTable (堆中没512Byte 映射在 card table 1 byte ) , 简单说 RS 里面存的是Region种存活对象的指针。 当Region中数据发生变化的时候 ,首先反映到Card Table 中的一个或者对个card上,RS通过扫面内部的Card Table 得知Region中内存使用情况和存活对象,在使用Region过程中,如果一个Region被填满了,分配内存的线程会重新选择一个新的Region,空闲Region被组织到一个基于链表的数据结构(LinkedList )中,这样可以快速找到Region.
G1 GC 可以分为 Young GC 和Mixed GC
年轻代GC:当年轻代达到一定的阈值,就开始年轻代的并发收集。将Eden Region中存活对象copy转移到Survivor的Region中,同时释放Eden Region 。 存活的时间够久就移到Old Reagion。
Mixed GC: 当Old Region占比达到一定的比例(通过 -XX:InitantingHeapOccupancyPercent 设置,默认45%)之后,会触发并行标记,然后就会进行Mixed GC。 Mixed GC 对一个叫做CSet的Region集合进行垃圾回收,其中包含了所有的年轻代Region和选取的一部分回收效益最好的Old Region。
并发标记的过程类似于CMS中的标记过程。
G1 可选优化参数
-
年轻代优化
-XX:G1NewSizePercent Java 堆初始化大小 ,默认是整个Java堆大小的5%,
-XX:G1MaxNewPercent 最大占用对内存的百分比,默认是60%
-XX:MaxGCPauseMills 每次目标停顿时间, 默认200ms
可以根据上述三个参数的调整来优化年轻代的垃圾回收
-
并行标记阶段优化
并行标记阶段, -XX:InitantingHeapOccupancyPercent 决定了什么时候初始化并行标记循环 默认值45%
-XX:ConcGCThreads 并发GC数量, 是-XX:ParallelGCThreads 的1/4 ,可以通过修改两个值来改变并线程的数量。
-
混合回收阶段优化
-XX:+PrintAdaptiveSizePoliy 开启