CMS (Concurent mark sweep)并发标记清除
- 步骤:
- 初始标记
- 并发标记
- 重新标记
- 并发清除
- 特点:并发收集、低停顿
- 问题
CPU敏感、浮动垃圾、碎片
G1(Garbage first)垃圾优先
![](https://img.haomeiwen.com/i11332031/21e8a6ad80701b13.jpeg)
不同于其他的分代回收算法、G1将堆空间划分成了互相独立的区块。每块区域既有可能属于O区、也有可能是Y区,且每类区域空间可以是不连续的(对比CMS的O区和Y区都必须是连续的)。这种将O区划分成多块的理念源于:当并发后台线程寻找可回收的对象时、有些区块包含可回收的对象要比其他区块多很多。虽然在清理这些区块时G1仍然需要暂停应用线程、但可以用相对较少的时间优先回收包含垃圾最多区块。这也是为什么G1命名为Garbage First的原因:第一时间处理垃圾最多的区块。
G1相比CMS
- G1在压缩空间方面有优势
- G1通过将内存空间分成区域(Region)的方式避免内存碎片问题
- Eden, Survivor, Old区不再固定、在内存使用效率上来说更灵活
- G1可以通过设置预期停顿时间(Pause Time)来控制垃圾收集时间避免应用雪崩现象
- G1在回收内存后会马上同时做合并空闲内存的工作、而CMS默认是在STW(stop the world)的时候做
- G1会在Young GC中使用、而CMS只能在O区使用
G1适合的场景
- 服务端多核CPU、JVM内存占用较大的应用(至少大于4G)
- 应用在运行过程中会产生大量内存碎片、需要经常压缩空间
- 想要更可控、可预期的GC停顿周期;防止高并发下应用雪崩现象
G1的四种回收操作方式
- YGC(不同于CMS)
- 并发阶段
- 混合模式
- full GC (一般是G1出现问题时发生)
就目前而言、CMS还是默认首选的GC策略
![](https://img.haomeiwen.com/i11332031/24a041bcc6ab272b.jpeg)
图中每个小区块都代表G1的一个区域(Region),区块里面的字母代表不同的分代内存空间类型(如[E]Eden,[O]Old,[S]Survivor)空白的区块不属于任何一个分区;G1可以在需要的时候任意指定这个区域属于Eden或是O区之类的。
G1 YoungGC在Eden充满时触发,在回收之后所有之前属于Eden的区块全变成空白。然后至少有一个区块是属于S区的(如图半满的那个区域),同时可能有一些数据移到了O区。
![](https://img.haomeiwen.com/i11332031/d532be1fe18e4cc8.jpeg)
- Young区发生了变化、这意味着在G1并发阶段内至少发生了一次YGC(这点和CMS就有区别),Eden在标记之前已经被完全清空,因为在并发阶段应用线程同时在工作、所以可以看到Eden又有新的占用
- 一些区域被X标记,这些区域属于O区,此时仍然有数据存放、不同之处在G1已标记出这些区域包含的垃圾最多、也就是回收收益最高的区域
- 在并发阶段完成之后实际上O区的容量变得更大了(O+X的方块)。这时因为这个过程中发生了YGC有新的对象进入所致。此外,这个阶段在O区没有回收任何对象:它的作用主要是标记出垃圾最多的区块出来。对象实际上是在后面的阶段真正开始被回收.
![](https://img.haomeiwen.com/i11332031/4305cec44cf2c175.jpeg)
像普通的YGC那样、G1完全清空掉Eden同时调整survivor区。另外,两个标记也被回收了,他们有个共同的特点是包含最多可回收的对象,因此这两个区域绝对部分空间都被释放了。这两个区域任何存活的对象都被移到了其他区域(和YGC存活对象晋升到O区类似)。这就是为什么G1的堆比CMS内存碎片要少很多的原因–移动这些对象的同时也就是在压缩对内存。
混合GC阶段会有survivor区的对象晋升到O区;另外,每次混合GC只是清理一部分的O区内存,整个GC会一直持续到几乎所有的标记区域垃圾对象都被回收,这个阶段完了之后G1会重新回到正常的YGC阶段。周期性的,当O区内存占用达到一定数量之后G1又会开启一次新的并行GC阶段.
网友评论