0
点赞
收藏
分享

微信扫一扫

023、JVM实战总结:一步一图:那JVM老年代垃圾回收器CMS工作时,内部又干了些啥?


    1、前文回顾

        对象都分配在新生代的Eden区,然后每次垃圾回收之后,存活对象都进入Survivor区,下一次垃圾回收后的存活对象都进入另外一个Survivor区。

    2、CMS垃圾回收的基本原理

        采用标记清理算法,先通过追踪GC Roots的方法,看看各个对象是否被GC Roots追踪到了,如果可以话,那就是存活对象,否则就是垃圾对象,先

        将垃圾对象都标记出来,然后一次性把垃圾对象都回收掉。

??问垃圾收集时,是标记存活还是标记垃圾?

DS推测:

1、YoungGC时,新生代存活对象少,采用复制算法把很少的存活复制到S区。代价小 

2、OldGC时,老年代存活对象多,虽然GC Roots追踪到的都是存活,但此时处理垃圾对象的代价小,所以标记未追踪到的对象-前提是先知道(标记)哪些是存活,然后清除。 

结论:YoungGG、OldGC都是要先标记存活对象。只是老年代需要额外标记垃圾对象,以便清除。

 

    3、如果Stop the World然后垃圾回收会如何?

        导致系统卡死时间过长,很多响应无法处理

        所以:CMS采取垃圾回收线程和系统工作线程尽量同时执行的模式来处理

    4、CMS如何实现系统一边工作的同时进行垃圾回收?        

  1. 初始标记 -  STW ,标记出来所有GC Roots直接引用的对象。很快。注意:方法的局部变量和类的静态变量是GC Roots。但是实例变量不是GC Roots
  2. 并发标记 - 此阶段与应用程序并行执行,垃圾回收线程对已有的对象进行GC Roots追踪,即对GC Roots直接关联的全部老年代对象进行追踪,而不是遍历所有老年代对象,这里的理解和文中表述不一致,需要进一步确认(作者回复:是从GCRoots开始追踪)
  3. 重新标记 - STW,重新标记下在第二阶段里新创建的一些对象,还有一些已有对象可能失去引用变成垃圾的情况。其实就是对在第二阶段中被系统程序运行变动过的少数对象进行标记,所以运行速度很快。
  4. 并发清理 - 清理掉之前标记为垃圾的对象即可,跟系统程序并发运行,不影响系统程序的执行

            

任务

STW

备注

速度

初始标记

STW

标记出来所有GC Roots直接引用的对象

速度很快

并发标记

--

垃圾回收线程对已有的对象进行GC Roots追踪

重新标记

STW

变动过的少数对象进行标记

速度很快

并发清理

--

清理掉之前标记为垃圾的对象

 

注意:方法的局部变量和类的静态变量是GC Roots。但是类的实例变量不是GC Roots

 

问:fullgc了,程序还并行运行,创建出来的对象放那?会一直触发fullgc吗?如果对象太多堆放不下,会等着fullgc完成吗?这个时候也是世界停止吗?

fullgc同时一般会伴随着一次Young GC,如果第一次fullGC过程中,因为新创建的对象原因又达到了触发fullGC的条件,首先还是会先Young GC,然后尝试放入新生代,但此时老年代还没有回收完成,再触发一次MajorGC没什么意义,因为重新标记会干了这个事情。

如果Young GC后,新创建的对象仍然放不进内存,需要等待MajorGC结束,如果MajorGC结束后仍然放不进去,就会OOM了。

 


举报

相关推荐

0 条评论