当初看文档的时候,了解到.net CLR中的Background GC机制,它类似于并发GC,当使得在做GC动作是,能够同时进行内存分配。这种机制显著的减少的stop the world这种事情,使得GC的干扰最小化。
当初认为.net这招非常优秀,足以鄙视JAVA,前几天看JVM的书,发现JVM也有类似的机制,但是不叫后台线程,而是称作CMS(Concurrent Mark Sweep)。
从名字就可以看出并发标记清除的意思。CMS机制仅针对老年代上的垃圾(.net的后台GC只在第2代上运行。年轻代上的垃圾由其他回收算法收集),它运行时,分成4个步骤:
初始标记,并发标记,重新标记和最后异步并发清除,其中初始标记和重新标记仍然会stop the world。从网上扒一张图,可以看到
初始标记其实就是标记root对象,速度很快,而并发标记,就是顺着root对象的引用链开始顺藤摸瓜的做标记,并发的进行标记,可以看到,此处GC线程和用户线程是同时运行的。
重新标记其实是对并发标记的一个补充修正,因为有些对象在并发标记后,又被释放掉或者又被重新引用,导致之前的标记不准确,重新标记一次。重新标记这个动作的速度是非常快的。接着并发清理时,又是和用户线程同时进行。因此,相比非并发的处理,这种机制有助于减少GC对用户程序的影响。
不过CMS也有缺点,它虽然不会stop the world,但是会占用CPU资源,会拖慢程序。还有一个缺点CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败(至于为什么会出现这种失败,书中也没说的很清楚)。这种失败导致另一次Full GC的产生。这招反而会影响性能。最后一个缺点是大多数标记清除算法共有的缺点,就是在回收后,可能会导致大量的碎片空间,当分配大对象的时候,但碎片太多找不到连续的大空间,也会导致一次Full GC。