垃圾回收器
串行垃圾回收器
- 单线程
- 堆内存较小,适合个人电脑
串行垃圾回收器回收过程如图:
JVM参数:-XX:+UseSerialGC= Serial + Serial0ld,打开串行回收器,Serial 工作在新生代,使用复制算法,Serial0ld工作在老年代,使用标记整理算法
吞吐量优先垃圾回收器
- 多线程
- 堆内存较大,需要多核cpu支持
- 单位时间内STW的时间最短
JVM参数:
-XX:+UseParalle1GC(新生代) ~ -XX :+UseParalle10ldGC(老年代),开启吞吐量优先垃圾回收器,1.8版本的jdk默认开启,开启一个,自动开启另一个
控制线程数:-XX:ParallelGCThreads=n
采用自适应的大小调节策略:-XX :+UseAdaptivesizePolicy
吞吐量优先垃圾回收器回收过程如图:
响应时间优先垃圾回收器
- 多线程
- 堆内存较大,需要多核cpu支持
- 尽可能让STW的单次时间最短
JVM参数:
开启响应时间优先垃圾回收器:-XX :+UseConcMarkSweepGC(基于标记清除算法的垃圾回收器,并且是并发的)~
-XX:+UseParNewGC(工作在新生代) ~ Serial0ld
控制CMS垃圾回收的时机:
-XX:CMSInitiatingoccupancyFraction=percent,因为并发清理阶段,其他用户进程可能也会产生垃圾,称为浮动垃圾,要预留空间
缺点:
响应时间优先垃圾回收器可能会因为内存碎片过多,导致并发失败,并发失败时会退化成Serial0ld,并发时间会变得很长
并发:垃圾回收器工作时,其他用户进程也能正常运行
响应时间优先垃圾回收器回收过程如下:
G1
定义:Garbage First
发展过程:
- 2004论文发布
- 2009 JDK 6u14体验
- 2012 JDK 7u4官方支持
- 2012 JDK 7u4官方支持
适用场景:
- 同时注重吞吐量(Throughput)和低延迟(Low latency),默认的暂停目标是200 ms
- 超大堆内存,会将堆划分为多个大小相等的Region
- 整体上是标记+整理算法,两个区域之间是复制算法
相关jvm参数:
-XX:+UseG1Gc
-XX:G1HeapRegionSize=size,设置划分区域的大小(1,2,4,8)
-XX:MaxGCPauseMillis=time,设置默认的暂停时间
G1垃圾回收阶段
如图所示:
Young Collection阶段:
白色区域为空闲区,E表示伊甸园区
新生代垃圾回收如图:
s表示幸存区,箭头表示复制算法
再工作一段时间:
o表示老年代,红色箭头表示晋升
Young Collection + CM阶段:
- 在Young GC时会进行GC Root的初始标记
- 老年代占用堆空间比例达到阈值时,进行并发标记(不会STW),由下面的JVM参数决定
-XX: InitiatingHeapOccupancyPercent=percent(默认45%)
如图:
当老年代占堆内存的45%时,就会进行并发标记
Mixed Collection阶段
会对E,S,O进行全面垃圾回收
- 最终标记(Remark)会STW
- 拷贝存活(Evacuation)会STW
如图:
部分老年代之间的红色箭头表示复制幸存对象,G1会根据你的最大暂停时间,有选择的进行回收,优先回收垃圾最多区域
各个回收器之间的Full GC和Minor GC
SerialGC
- 新生代内存不足发生的垃圾收集- minor gc
- 老年代内存不足发生的垃圾收集- full gc
ParallelGC
- 新生代内存不足发生的垃圾收集- minor gc
- 老年代内存不足发生的垃圾收集- full gc
CMS
- 新生代内存不足发生的垃圾收集- minor gc
- 老年代内存不足,并发失败后才叫Full GC
G1
- 新生代内存不足发生的垃圾收集- minor gc
- 老年代内存不足,当老年代内存和堆内存占比达到阈值以上,会触发默认标记阶段和混合收集阶段,这两个阶段工作过程中,如果回收速度高于新产生垃圾速度时,这个时候还是处于并发垃圾收集阶段,还不算Full GC,如果回收速度小于新产生垃圾速度时,这个时候会并发失败,退化为串行收集,这个时候叫Full GC
Young Collection跨代引用
新生代回收的跨代引用(老年代引用新生代)问题
当查找新生代对象的根对象时,有一部分根对象来自于老年代,但是老年代中对象很多,于是采用卡表技术,细分老年代区域
如图:
如果有一个对象引用了新生代,就把卡表标记为脏卡,以后只需要查找脏卡对象
Remark(重标记)
并发标记阶段时的对象处理状态:
黑色的表示处理完成,结束时会被保留下来
灰色表示处理当中
白色表示尚未处理
当对象引用发生改变时,jvm会给对象一个写屏障,然后把被引用的队列放入队列中,等整个并发阶段结束,进入重新标记阶段,STW,重新标记的线程会检查队列中的对象,如果有强引用,就会保留该对象