各类GC及触发条件

针对HotSpot VM的实现,它里面的GC其实准确分类只有两大种:

  • Partial GC:并不收集整个GC堆的模式
  • Young GC:只收集young gen的GC
  • Old GC:只收集old gen的GC。只有CMS的concurrent collection是这个模式
  • Mixed GC:收集整个young gen以及部分old gen的GC。只有G1有这个模式
  • Full GC:收集整个堆,包括young gen、old gen、perm gen(如果存在的话)等所有部分的模式。

Major GC通常是跟full GC是等价的,收集整个GC堆。但因为HotSpot VM发展了这么多年,外界对各种名词的解读已经完全混乱了,当有人说“major GC”的时候一定要问清楚他想要指的是上面的full GC还是old gen。

最简单的分代式GC策略,按HotSpot VM的serial GC的实现来看,触发条件是:
**young GC:**当young gen中的eden区分配满的时候触发。注意young GC中有部分存活对象会晋升到old gen,所以young GC后old gen的占用量通常会有所升高。
full GC:当准备要触发一次young GC时,如果发现统计数据说之前young GC的平均晋升大小比目前old gen剩余的空间大,则不会触发young GC而是转为触发full GC(因为HotSpot VM的GC里,除了CMS的concurrent collection之外,其它能收集old gen的GC都会同时收集整个GC堆,包括young gen,所以不需要事先触发一次单独的young GC);或者,如果有perm gen的话,要在perm gen分配空间但已经没有足够空间时,也要触发一次full GC;或者System.gc()、heap dump带GC,默认也是触发full GC。这就是FullGC的触发条件
HotSpot VM里其它
非并发
GC的触发条件复杂一些,不过大致的原理与上面说的其实一样。
当然也总有例外。Parallel Scavenge(-XX:+UseParallelGC)框架下,默认是在要触发full GC前先执行一次young GC,并且两次GC之间能让应用程序稍微运行一小下,以期降低full GC的暂停时间(因为young GC会尽量清理了young gen的死对象,减少了full GC的工作量)。这是HotSpot VM里的奇葩嗯。

并发GC的触发条件就不太一样。以CMS GC为例,它主要是定时去检查old gen的使用量,当使用量超过了触发比例就会启动一次CMS GC,对old gen做并发收集。这里就是只回收老年代了!

从携程apollo拷贝过来的JVM参数,看一下他们用了哪些JVM参数

-Xms6144m -Xmx6144m -Xss256k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=384m -XX:NewSize=4096m -XX:MaxNewSize=4096m -XX:SurvivorRatio=8
-XX:+UseParNewGC -XX:ParallelGCThreads=4 -XX:MaxTenuringThreshold=9 -XX:+UseConcMarkSweepGC -XX:+DisableExplicitGC -XX:+UseCMSInitiatingOccupancyOnly -XX:+ScavengeBeforeFullGC -XX:+UseCMSCompactAtFullCollection -XX:+CMSParallelRemarkEnabled -XX:CMSFullGCsBeforeCompaction=9 -XX:CMSInitiatingOccupancyFraction=60 -XX:+CMSClassUnloadingEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSPermGenSweepingEnabled -XX:CMSInitiatingPermOccupancyFraction=70 -XX:+ExplicitGCInvokesConcurrent -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationConcurrentTime -XX:+PrintHeapAtGC -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Duser.timezone=Asia/Shanghai -Dclient.encoding.override=UTF-8 -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom

UseCMSCompactAtFullCollection和CMSFullGCsBeforeCompaction是搭配使用,两个参数缺一不可,才能实现指定次数Full GC后对老年代进行压缩,因为老年代是标记清除。

-XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark指导垃圾回收机制在进行Full GC和CMS remark phase之前收集年轻态。其结果是提升性能,因为在年轻态和老态之间不存在检查引用。

-XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=

缺省的 CMS GC使用的启发式规则触发垃圾回收,这会让GC不太能预测,一般直至老生代空间被几乎占满后才会启动垃圾回收,Initiating设置能够使得在老生代变满之前完成回收,避免Full GC (这就意味着整个应用程序暂停无响应stop-the-world pause). -XX:+UseCMSInitiatingOccupancyOnly 阻止使用启发式规则 -XX:CMSInitiatingOccupancyFraction 通过JVM应该在什么时候启动触发回收,它会在heap中创建一个buffer,这个缓冲当CMS工作时能用数据填充,其内存被消耗的速度百分比可衡量老生代生产环境中的消耗。这个百分比数值应该小心选择,太小CMS太频繁,太大CMS启动频率太少,并发模式可能会失败。

XX:+CMSParallelRemarkEnabled

启动并发标记,提高效率。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章