面试官:你了解JVM的内存管理模型吗?
菜鸟:你指的是哪种垃圾回收器?
分代模型
年轻代的垃圾是容易被回收的垃圾,而老年代里是不容易被回收的垃圾。根据工业统计,年轻代的一次垃圾回收,就能回收接近90% 的垃圾。
JDK1,7还有永久代
年轻代使用的是Copying算法。
老年代使用的是Mark Compact 或者 Mark Sweep 算法
年轻代Copy过程:
第一次GC,eden里存活的对象被copy到 s1里,eden里剩余的全部被清除。
第二次GC,eden和s1里存活的对象copy到s2里,eden和s1里剩余的被清除。
死三次GC,eden和s2里存活的对象copy到s1里,eden和s2里剩余的被清除。
…………
依次循环。
有些对象实在无法被清除,到了一定年龄就会进入老年代。
年轻代与老年代的比例:1:2
eden与s1和s2的比例:8:1:1
垃圾回收器组合
分代模型里的垃圾回收器一定是成对出现的。
常见的有三种:
- ParNew + CMS
- Serial + Serial Old
- Parallel Scavenge + Parallel Old (1.8默认)
JDK1.8 可用分代模型,也可不用分代模型,可用G1。JDK1.9默认G1
Serial + Serial Old
现在很少使用了,是最早的垃圾回收器组合。
当有线程在工作时,突然有一个单线程的垃圾回收器来回收垃圾,所有工作的线程都有停止,等垃圾回收器工作完成以后,所有工作的线程才能恢复工作。所以在实际业务中,会出现卡顿的现象,很有可能是垃圾回收器在工作。
Parallel Scavenge + Parallel Old
当有线程在工作时,突然有一个多线程的垃圾回收器来回收垃圾,所有工作的线程都有停止,等垃圾回收器工作完成以后,所有工作的线程才能恢复工作。所以在实际业务中,会出现卡顿的现象,很有可能是垃圾回收器在工作。
Parallel Scavenge 与 Serial 的区别就是多线程和单线程
ParNew + CMS
因为Serial和Parallel Scavenge不能与CMS配对,为了与CMS配对,才有了ParNew。
CMS工作原理
初始标记:再根据根可达性算法标记垃圾的时候,此时并不会往下继续执行,而是只标记根对像就可以了,所以此处的停顿时间也是很少的,基本上也就是几百个毫秒,可以接收。
并发标记:垃圾回收线程与业务线程同时运行,在运行中如有业务线程产生了垃圾,会被垃圾回收吧线程直接标记为垃圾。但这里会有一些问题,如果一个对象被标记为垃圾后,又有其他对象指向了它,如果这个对象被当做垃圾处理会出问题,此时就会产生错标的问题。此处也有可能产生浮动垃圾,就是没有被标记的垃圾,但是没关系,等下次标记的时候再次处理。
重新标记:就是为了解决错标的问题。时间也和短。
并发清理:清理被标记的垃圾。此处也有可能产生浮动垃圾,没关系,等下次被标记为垃圾然后清除。
CMS错标对象修正的算法
三色标记算法
第一种情况:B—>D消失,增加 A—>D
正常情况
此时,垃圾回收器标记,标记完了,ABD都不是垃圾。
运行过程之中,B指向D的引用消失了,D成了浮动垃圾,等下次执行的时候会被标记为垃圾清理掉。
在B指向D的引用消失的与此同时,A增加了指向D的引用。因为A已经被标记为黑色了,(被标记为黑色是他的孩子都已经被标记过了,不会被重新标记),所以D,不会被找到,就会当做垃圾处理掉。
如何解决这个问题:
-
CMS解决方式
Incremental Update
就是把A变成灰色,就可以再次扫描标记了。
会产生的问题:并发标记,产生漏标。