这是我开通博客园的第一篇文章,有错误的地方,请大家指正,之所以开通博客园,是受到以为学长的影响,看着他在博客园的博客,我知道写博客不仅是自我复习的一个过程,也是一个和别人沟通的窗口,所以我打算向学长学习,以后多记录博客,加深知识点的印象。
CMS和G1的区别是我最近在面试过程中经常被问到的一个问题,虽然能答出几点出来,但是自己并不太满意,网上关于两者的对比也没有特别完善的文章,于是打算记录下这边文章
首先我把答案给出来,然后再去分析为什么会这样
|
CMS |
G1 |
JDK版本 |
1.6以上 |
1.7以上 |
回收算法 |
标记——清除 |
标记——整理 |
运行环境 |
针对70G以内的堆内存 |
可针好几百G的大内存 |
回收区域 |
老年代 |
新生代和老年代 |
内存布局 |
传统连续的新生代和老年代区域 |
Region(将新生代和老年代切分成Region,默认一个Region 1 M,默认2048块) |
浮动垃圾 |
是 |
否 |
内存碎片 |
是 |
否 |
全堆扫描 |
是 |
否 |
回收时间可控 |
否 |
是 |
对象进入老年代的年龄 |
6 |
15 |
空间动态调整 |
否 |
是(新生代5%-60%动态调整,一般不需求指定) |
调优参数 |
多(近百个) |
少(十几个) |
1、CMS
CMS(Concurrent Mark Sweep),我们可以轻易地从命名上看出,它是一个并发的,然后是基于标记——清理的垃圾回收器,它清理垃圾的步骤大致分为四步:
- 初始标记
- 并发标记
- 重新标记
- 并发清理
(图片是出自网上,如有侵犯请联系我,谢谢)
初始标记只要是找到GC Roots,所以是一个很快的过程,并发标记和用户线程一起,通过GC Roots找到存活的对象,重新标记主要是修复在并发标记阶段的发生了改变的对象,这个阶段会Stop the World;
并发清理则是保留上一步骤标记出的存活对象,清理掉其他对象,正因为采用并发清理,所以在清理的过程中用户线程又会产生垃圾,而导致浮动垃圾,只能通过下次垃圾回收进行处理;
因为cms采用的是标记清理,所以会导致内存空间不连续,从而产生内存碎片
此处要清楚,CMS的垃圾回收的内存模型还是以我们常用的新生代,老年代的结构,如下图所示:
2.G1
G1(Garbage-First),以分而治之的思想将堆内存分为若干个等大的Region块,虽然还是保留了新生代,老年代的概念,但是G1主要是以Region为单位进行垃圾回收,G1的分块大体结果如下图所示:
G1垃圾回收器的它清理垃圾的步骤大致分为四步:
- 初始标记
- 并发标记
- 最终标记
- 复制回收
初始标记和并发标记和CMS的过程是差不多的,最后的筛选回收会首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划
因为采用的标记——整理的算法,所以不会产生内存碎片,最终的回收是STW的,所以也不会有浮动垃圾,Region的区域大小是固定的,所以回收Region的时间也是可控的
同时G1 使用了Remembered Set来避免全堆扫描,G1中每个Region都有一个与之对应的RememberedSet ,在各个 Region 上记录自家的对象被外面对象引用的情况。当进行内存回收时,在GC根节点的枚举范围中加入RememberedSet 即可保证不对全堆扫描也不会有遗漏。
以上就是CMS和G1的对比过程,如果面试中能回答出这些内容应该就能博得面试官一笑,盗图可耻,匿了