今天,我们一起看一下JVM的垃圾回收器。
垃圾回收器是在堆区进行回收,堆区分为新生代和老年代,不同区域由于生成/淘汰对象的频率,使用不同的垃圾回收器。主要有以下几种组合:
先来说说新生代使用的几种垃圾回收器吧!
他们的共同点:均使用复制算法进行垃圾回收
Serial 是一个 stop-the-world(STW)。
垃圾回收时,工作线程全停止,等着垃圾回收线程进行回收,这时候用户是得不到任何反馈的。(耗时较长的垃圾回收耗费大约几十秒~1分钟)。
-XX:+UseSerialGC 设置新生代使用Serial GC
safe point 含义是在程序运行到安全点上的时候再STW,而不是立刻停止。
比如:解锁操作完成之后再停止,然后进行垃圾回收。
-XX:+UseSerialGC 使用命令
默认线程数与CPU数量相同。可通过-XX:ParallelGCThreads
来设置线程数,同样存在STW问题。
-XX:+UsePerNewGC 使用命令
它是多线程的STW垃圾回收器,多个线程共同并行回收。
注意:
Parallel Scavenge是并行,不是并发。
CMS是并发,回收线程和工作线程同时进行。
但随着内存越来越大,线程数越来越多,CPU会将资源耗费在线程切换上,因此线程数不可被无限增多。
吞吐量=代码运行时间/(代码运行时间+垃圾收集时间)
-XX:+UseParallelGC 可以设置新生代使用这个并行回收器
-XX:+UseAdaptiveSizePolicy 打开自适应模式,在这种模式下,新生代的大小、eden、from/to的比例,以及晋升老年代的对象年龄参数会被自动调整,以达到在堆大小、吞吐量和停顿时间之间的平衡点。
-XX:MaxGCPauseMillis 设置最大垃圾收集停顿时间。可用把虚拟机在GC停顿的时间控制在MaxGCPauseMillis范围内,将MaxGCPauseMillis设置的很小,可以减少GC停顿时间,但是会导致GC频繁,从而增加了GC的总时间,降低了吞吐量。所以需要根据实际情况设置该值。
-XX:GCTimeRatio 设置吞吐量大小,它是一个0到100之间的整数,默认情况下他的取值是99,那么系统将花费不超过1/(1+n)的时间用于垃圾回收,也就是1/(1+99)=1%的时间。
下面介绍一下老年代的几种垃圾回收器
SerialOld是Serial回收器的老年代回收器版本,它同样是一个单线程回收器。使用标记整理(压缩)算法。
作为CMS收集器的后备预案,如果CMS出现Concurrent Mode Failure
,则SerialOld将作为后备收集器。
ParallelOldGC回收器是一种多线程的回收器,和新生代的ParallelGC回收器一样,关注吞吐量的回收器。使用标记整理(压缩)算法。
-XX:+UseParallelOldGC 设置老年代使用该回收器
-XX:+ParallelGCThreads 设置垃圾收集时的线程数量。
全称:Concurency Mark Swap GC,即并发标记清除GC,使用标记清除算法。
特点:
XX:CMSInitiatingoccupancyFraction
来指定。CMS 分为4个阶段
初始标记:需要STW,因为初始的垃圾并不多,因此耗费的时间不长;
并发标记:垃圾回收线程和工作线程同时执行。一边产生垃圾,一边标记;
重新标记:对在并发标记的过程中新产生的垃圾进行重新标记,或者原来被标记的垃圾变为不是垃圾。因为新产生的垃圾不多,所以时间也不是很长;
并发清理:清理的过程也会产生新的垃圾“浮动垃圾”,需要等下一次CMS重新运行的时候再次清理。
-XX:+UseCMSCompactAtFullCollection 可以使CMS回收完成之后进行一次碎片整理
-XX:CMSFullGCsBeforeCompaction 默认为0 设置经过多少次FGC才进行压缩
Concurrent Mode Failure
产生:if the concurrent collector is unable to finish reclaiming the unreachable objects before the tenured generation fills up, or if an allocation cannot be satisfiedwith the available free space blocks in the tenured generation, then theapplication is paused and the collection is completed with all the applicationthreads stopped
这个现象在日志里打印出来是PromotionFailed
以上两个问题的解决方案类似:降低触发CMS的阈值,保持老年代有足够的空间。
–XX:CMSInitiatingOccupancyFraction 92
可以理解为,老年代内存到达92% 的时候,CMS才工作。
可以降低这个值,让CMS保持老年代足够的空间。
可以使用命令查看默认值:
java -XX:+PrintFlagsFinal -version | grep CMSInitiatingOccupancyFraction
-XX:+UseConcMarkSweepGC 设置老年代使用该回收器。
-XX:+UseCMSCompactAtFullCollecion 可以使CMS回收完成之后进行一次碎片整理
-XX:CMSFullGCsBeforeCompaction 默认为0 设置经过多少次FGC才进行压缩
-XX:ConcGCThreads 设置并发线程数量。
G1是逻辑分代,物理不分代(物理分代就是内存里确实有这样一块空间)
欢迎大家评论,如果本文对您有帮助,请点个赞,您的点赞对我很重要!这次一定!感谢!!!
转发请注明出处呦!感谢!!!