JVM系统自学笔记6--垃圾回收器

一、三种类型介绍

1、串行

  • 单线程
  • 堆内存较小,适用于个人电脑

2、吞吐量优先

  • 多线程
  • 堆内存大,多核cpu
  • 单位时间内STW时间最小 0.2+0.2 = 0.4----单位时间内,尽可能少调用垃圾回收

3、响应时间优先

  • 多线程
  • 堆内存大,多核cpu
  • 尽可能STW单次时间减小 0.1+0.1+0.1+0.1+0.1=0.5-----调用垃圾回收时,STW尽可能小

二、串行垃圾回收器

image.png

其中新生代使用Serial,老年代使用SerialOld垃圾回收器。

  • Serial垃圾回收器使用的是复制算法,新生代中对象变化很大,存活对象相对于其他分区比较少,使用复制算法能够有效地提高效率。

  • SerialOld使用的是标记整理算法,老年代存活的都是些价值很高的对象,回收的对象数量很少,整理耗用很小,复制存活对象会消耗更多的时间,且会耗用多一倍的内存空间(老年代本身空间就已经较大)。

  • 复制存活对象会消耗更多的时间,且会耗用多一倍的内存空间(老年代本身空间就已经较大)。

三、吞吐量优先回收器

MaxGCPauseMillis设置回收停顿的最大时间,收集器尽可能将垃圾回收消耗时间保持在这个数值之下,但是并不是把这个数设置越小,垃圾收集就越快。

  • 停顿时间减少是以牺牲吞吐量和新生代空间换来的,系统会将新生代内存降低,来达到每次回收停顿时间缩小,但是这也导致了停顿次数增加,总停顿时间并没有减少,吞吐量减小。

GCTimeRatio设置一个1-99的整数,*1/(1+X)*表示垃圾回收时间占总时间的比率,整数设置越大,吞吐量越小。

  • 这又回到上面那个问题,整数设置越大相当于停顿时间减少,系统会减少新生代内存,导致停顿增加,吞吐量减小。

所以这两个参数不可一味的增加某一个,他们互相制约,寻找一个平衡。

-XX:+UseAdaptiveSizePolicy 系统会根据系统运行情况修改新生代大小(-Xmn),Eden和Survivor比例(-XX:SurvivorRatio),晋升老年代对象年龄(-XX:PretenureSizeThreshold)等参数;来提供最合适的停顿时间和最大吞吐量。

总结
对于不是很了解收集器运作的开发人员来说,ParallelGC是个更好的选择。事先设置好堆大小-Xmx,然后设置 MaxGCPauseMillis(重视停顿时间)或者GCTimeRatio(重视吞吐量);设置完优化目标,剩下的具体参数修改交给系统自己。
这也是ParallelGCParNew一个重要的区别。

四、响应时间优先垃圾收集器

老年代使用CMS垃圾回收器,使用的是标记清除算法

新生代ParNewGC垃圾收集器,复制算法(ParNewGC多线程版本的Serial)。

-XX:ParallelGCThread=n,并行线程数,一般为cpu核心数,图中N=4。

-XX:ConcGCThreads=threads,一般设置为n/4,并发垃圾回收线程数

-XX:CMSInitiatingOccupancyFraction=percent,达到比例就会出发老年代垃圾回收。

  • jdk1.6将这一值从1.5中的68改为92,为了防止频繁的触发老年代垃圾回收;
  • 为什么要设置这一比例?
    • 因为在并发垃圾清理的同时,其它用户线程也在运行,产生的浮动垃圾CMS当前批次中难以处理,只能留到下次GC;也正是因为如此,所以需要留下空间给用户线程运行所产生的对象使用。
  • 如何设置最好?
    • 在内存无法满足运行需要时,会出现Concurrent Mode Failure失败,VM会使用Serial Old代替CMS对老年代中垃圾对象进行整理,停顿时间更长,比例设置过高,更加容易触发Concurrent Mode Failure失败,影响性能(Serial Old暂停所有用户线程防止产生更多的对象,同时可以清理内存碎片)。
    • 所以项目产生对象不是很快可以将这一比例设置高一点,这样既不会很快出现Concurrent Mode Failure失败,也不会太容易触发GC。
  • 因为CMS老年代使标记-清除算法,会产生很多碎片内存,会给大对象分配内存带来麻烦,则会出现老年代内存很充裕,但是大对象放不进去,不得不触发FULL GC;-XX:+UseCMSCompactAtFullCollection默认开启,在CMS要开始FULL GC时,开启内存碎片的合并,无法并发,整理时间变长。

-XX:CMSFullGCsBeforeCompaction,设置执行多少次不压缩的FULL GC后,执行一次带压缩的FULL GC。

并发标记、重新标记remark

  • 图中黑色表示已经处理完毕,灰色表示正在处理,白色表示还未处理。
  • 灰色引用白色对象,由于是并发收集,所以该对象存在被其他线程取消引用的可能。
  • 当然也有可能将本来已经被回收的没有被引用的白色对象重新被引用,但是对象已经被回收,无法再引用。
  • 采用per-write barrior 在引用关系未改变之前设置屏障并放入satb_mark_queue队列中,直到收集完毕。

发布了171 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/QilanAllen/article/details/105634626