垃圾收集器

发布时间 2023-12-01 17:32:57作者: twfplayer

G1垃圾收集器

遵循分代收集理论设计的,但其堆内存的布局与其他收集器有非常明显的差异:G1不再坚持固定大小以及固定数量的分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。收集器能够对扮演不同角色的Region采用不同的策略去处理,这样无论是新创建的对象还是已经存活了一段时间、熬过多次收集的旧对象都能获取很好的收集效果。
Region中还有一类特殊的Humongous区域,专门用来存储大对象。G1认为只要大小超过了一个Region容量一半的对象即可判定为大对象。每个Region的大小可以通过参数 -XX:G1HeapRegionSize 设定,取值范围为1MB~32MB,且应为2的N次幂。而对于那些超过了整个Region容量的超级大对象,将会被存放在N个连续的Humongous Region 之中,G1的大多数行为都把 Humongous Region 作为老年代的一部分来进行看待。

就是说将堆内存划分后标记区块而不是标记某一对象占用的内存,垃圾收集时对每一不同的内存区域执行不同的收集策略,对于大对象,有专门的大存储空间,也可以合用多个大空间。垃圾收集以单个空间作为单位,而不是以整个空间。对新生代和老年代所处的空间不固定而是动态的区域集合。根据每个区域的回收价值维护回收优先级。

CMS(Concurrent Mark Sweep)收集器

是一种以获取最短回收停顿时间为目标的收集器。从名字上就可以看出CMS收集器是基于标记-清除算法实现的,它的运作过程分为四个步骤,包括:

  1. 初始标记(CMS initial mark);
  2. 并发标记(CMS concurrent mark);
  3. 重新标记(CMS remark);
  4. 并发清除(CMS concurrent sweep)。
    其中初始标记、重新标记这两个步骤仍然需要“Stop The World”。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快;并发标记阶段就是从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行;而重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间通常会比初始标记阶段稍长一些,但也远比并发标记阶段的时间短;最后是并发清除阶段,清理删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。由于在整个过程中耗时最长的并发标记和并发清除阶段中,垃圾收集器线程都可以与用户线程一起工作,所以从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。

就是先快速标记根直接关联的对象,然后再并发的与用户线程同步标记对象,标记完成后通过并发过程中的记录修正标记(主要是防止清理了新增的对象),最后清理已死亡对象,由于不需要移动,所以也可以并发。
主要是为了不让垃圾收集的耗时操作停顿,影响用户线程,通过快速标记和并发思想尽可能缩短垃圾收集时间。

缺点

CMS收集器对处理器资源非常敏感。在并发阶段,它虽然不会导致用户线程停顿,但却会因为占用了一部分线程(或者说处理器的计算能力)而导致应用程序变慢,降低总吞吐量。
然后,由于CMS收集器无法处理“浮动垃圾”(Floating Garbage),有可能出现“Con-current Mode Failure”失败进而导致另一次完全“Stop TheWorld”的Full GC的产生。
还有最后一个缺点,CMS是一款基于“标记-清除”算法实现的收集器,这意味着收集结束时会有大量空间碎片产生。空间碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很多剩余空间,但就是无法找到足够大的连续空间来分配当前对象,而不得不提前触发一次Full GC的情况。

占用部分线程(减少了停顿时间)、在并发标记的过程中变动(删除了引用)直到下一次gc才能清除的就叫浮动垃圾、标记清除算法,空间利用率低,没有合适得位置就只能触发Gc来腾出空间