设计目标
服务端的垃圾回收器
通过垃圾回收并发线程保障更短的垃圾回收时间,特别是老年代中存活对象比较多的应用
适用于多处理器的机器(垃圾回收多线程,并于用户线程并发,如果只有一个处理器(cpu),那么必然只能保证串行)
实现方案
包含minor collection和major collection
major collection为了提高回收效率,使用了多线程进行扫描和回收
在major collection的过程中,总共会有两次停顿,分别是多线程进行初始化标记,和重新标记阶段,后者的停顿时间就是前一个停顿时间得了两倍
同时minor collection是通过parallel collecter进行的,同样也有初始化标记,因此会STW
适用场景
多处理器的服务器
老年代中存回对象比较多的应用(通过多线程回收,以及很短的停顿时间来尽快的进行对象标记和垃圾回收)
其他
Conccurent Mode Failure(并发模式失败):何为并发模式失败?CMS的标记和回收过程中有几个是并发阶段,是什么使得这个并发阶段无法进行下去呢?是谁无法进行下去,是GC 线程还是用户线程?这里无法进行下去的并发阶段肯定是应用程序的线程,应用程序的线程执行过程中,必然会创建更多的对象,这时如果对象没法分配到内存空间,那么就会引起并发模式失败,就会是得当前的CMS垃圾回收线程中断,转而用Full GC的方式进行垃圾回收。
那是什么原因导致对象没法分配内存空间呢?有两个原因
首先是老年代中没有足够的连续空间以盛放从新生代晋升下来的对象。即使老年代中总的空闲空间可能还有很多。
该现象触发原因是因为CMS使用的垃圾回收算法是标记-清理算法,使得内存中连续的空间都比较小。
其次是垃圾回收还来不及释放空间
该现象触发的原因是因为用户线程太繁忙了,创建的对象太快了,使得垃圾回收速度显得比较慢。
OutOfMemoryError异常发生契机:注意,OOM发生的时候并不是对空间完全满了,而是当98%的整体时间花在了GC上,但是只回收了2%的空间,这时候就会发生OOM。这是为了防止应用程序一直在执行,但是因为内存空间问题,导致执行速度很慢。
浮动垃圾:因为CMS在垃圾回收阶段中有部分阶段是用户线程和GC线程并发进行的。并且标记阶段分成了几个阶段。前一个阶段标记为存活的对象,在后续的阶段中因用户线程执行完毕,这些对象就不被引用了。但是还是被标记为存活对象的。就是所谓浮动垃圾
CMS的停顿:CMS有两个停顿,一个是初始化标记时从root对象开始扫描的过程。还有一个停顿是在并发标记阶段,该阶段会把前几个阶段产生的新对象进行重新扫描标记,如果还有被引用的对象,那么应该标记为存活对象
并发标记阶段:并发标记分为两部分,首先是初始标记和重新标记阶段。在并发标记阶段,GC线程会使用原本用于应用程序线程的资源,因此对于计算密集型的应用来说,吞吐量会有相应的下降,即使用户线程也一直在执行。
何时触发major collection:如果等到内存用满了才进行major collection,那么就会很容易发生Concurrent Mode Failure问题。所以CMS提供了两种方式触发major collection
CMS会通过历史的回收情况,预估下一次的回收时间。
如果堆内存使用率超过了92%,这时候会触发major collection
调度暂停(scheduling pause):年轻代的young collection产生的停顿和major collection产生的停顿是独立的。因此有可能两个停顿相隔的比较接近,就相当于一个比较长的停顿。CMS为了解决这个问题,将重新标记阶段安排在两次young collection暂停之间
增量模式(incremental mode):针对处理器较少的服务器中,由于CMS在并发标记阶段中的并发重新标记和并发清除阶段会使用一个CPU来处理,因此此时的用户线程就会被阻塞,导致那些用户响应比较严格的服务来说是比较致命的。因此CMS在这种情况下,会将并发重新标记和并发清除标记阶段分为几个阶段,方便让用户线程也能同时进行