内存系列相关文章
介绍两个垃圾回收器
1.CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿为目标的收集器。很大一部分的Java应用都集中在互联网站或者B/S系统的服务器端上,这类应用尤其重视服务的响应速度,希望停顿时间最短,给用户带来较好的体验,CMS收集器就非常符合这类应用的需求。
从名字上可以看出这款收集器是基于“标记--清除”算法实现的,整个过程分为四个阶段:
- 初始化标记
- 并发标记
- 重新标记
- 并发清除
其中初始化标记和重新标记两个步骤需要停止其他工作线程。初始化标记仅仅标记GC Roots能直接关联的对象,速度很快,并发标记就是GC Roots Tracing的过程,重新标记阶段是为了修正并发标记期间,因用户程序继续运行而导致的标记产生变动的那一部分对象的标记记录,这个极端的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记时间短。
在垃圾回收过程中最耗时的是并发标记和并发清除阶段,由于这两个阶段是并发的,收集器线程可以和用户线程一起工作,所以总体上来说:CMS收集器在内存回收过程中与用户线程一起是并发执行的。
它的有点是:并发收集,低停顿,Sun的一些官方文档中也称之为并发低停顿收集器。但是CMS海运达不到完美的程度,它它有以下三个明显的缺点:
- CMS收集器对CPU资源非常敏感。其实,面向并发设计的程序都对CPU资源比较敏感。在并发阶段,它虽然不会导致用户线程停顿,但是因为它占用了一部分CPU资源,从而导致应用程序变慢。CMS默认开启的回收线程数是(CPU数量+3)/4,也就是说当CPU在4个以上时,并发回收线程最多占用不超过25%的CPU资源。但是当CPU不足4个时,那么CMS对用户线程的影响可能变得很大,如果CPU负载本来就很大时,还要分出一半的运算能力去执行收集器线程,就回导致用户程序的执行执行速度忽然降低50%。为了解决这种情况,虚拟机提供了一种称为“增量式并发收集器”的CMS收集器的变种,所做的事情和单CPU年代PC机操作系统使用抢占式来模拟多任务机制的思想一样,就是在并发标记和并发清除时让GC线程线程,用户线程交替运行,尽量减少GC线程独占CPU资源的时间,这样整个垃圾回收过程就回更长,但对用户程序的一ing想就会显得少一些。
- CMS收集器无法处理浮动的垃圾。由于CMS并发清理阶段用户线程还在运行着,伴随着程序的运行必然还会有新的垃圾产生,这一部分垃圾出现在标记过程之后,CMS是无法收集处理掉这部分内存的,这能在下一次GC时才能回收。由于在垃圾回收阶段用户线程还要继续运行,即还需要预留足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再去进行收集,需要预留一部分空间提供并发收集时程序的运行使用。在默认的情况下,CMS收集器在老年代使用了68%的空间后就回被激活。
- 由于CMS是一款基于“标记—清除”算法实现的收集器,那么它必然有一个缺点:收集结束时会产生大量的空间碎片。空间碎片过多时,将会给大对象分配带来很大的麻烦,往往会出现还有很大的内存空间,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC。
2.G1收集器
G1收集器是垃圾回收器理论进一步的发展产物,他与前面的CMS收集器相比有两个明显的改进:一是G1收集器是基于”标记—整理“算法实现的收集器,也就是说他不会产生空间碎片,这对于长时间运行的应用系统来说是非常重要的。二是它可以非常精确的控制停顿,既能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾回收上的时间不得超过N毫秒,这几乎已经是实时Java的垃圾回收器的特征了。
G1收集器可以实现在基本不牺牲吞吐量的前提下完成低停顿的内存回收,这是由于它能够极力的避免全区域的垃圾收集,之前的收集器进行收集的范围都是整个新生代或者老年代,而G1将整个Java堆(包括新生代和老年代)划分为多个大小固定的独立区域(Region),并且跟踪这些区域里面的垃圾堆积程度,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域(这就是Garbage First名称的来由)。区域划分及有优先级的区域回收,保证了G1收集器在有限的时间内可以获得最高的收集效率。