×

Java垃圾回收复制算法为什么要有两个Survivor

96
缄默的石头
2017.03.25 18:15* 字数 823

新生代复制算法为什么要有两个Survivor

  1. 为什么要有survivor

    如果没有survivor,新生代在进行一次minor GC后存活的对象无处安放,只能升级到老年代中,这样老年代很快就会装满,进行major gc,也就是FULL GC,会出现stop the world,应用无法做出响应。这种情况下,要么增加老年代的大小,从而来降低Full GC的频率,这样做的缺点就是:由于老年代空间过大,Full GC的执行时间会变长,系统的响应性急剧下降;要么减小老年代的大小,Full GC消耗的时间变短,系统的响应性增强,但是Full GC发生的频率增多,系统的吞吐量下降(吞吐量=代码执行时间/(代码执行时间+垃圾回收时间))

  2. 只有一个survivor是什么情况
    鉴于第一种情况,所以要有survivor的存在。当新生代发生minor GC时,可以将存活的对象转移到survivor中,直到存活的对象old enough再转移到老年代中,从而减小进入老年代对象的数量,减少发生Full GC的次数。
    那么为什么复制算法要搞两个survivor呢?
    如果只有一个survivor,当Eden区满的时候,发生一个minor gc,如果有存活对象,将存活对象转移到survivor中,那么下次Eden区再满的时候,再次minor gc,这时Eden区和Survivor都有存活的对象(都部分被清空)此时空间是不连续的。怎么做会比较好呢?

    1. 试图将Eden区存活的对象转移到survivor中,努力适应这种不连续的空间。但是不连续的空间会导致再分配大对象的时候,由于没有连续的空间来分配,会导致提前垃圾回收
    2. 将survivor中的所有存活对象向下移动来消除碎片,然后将所有的存活对象移入其中。这样做会降低效率。
    3. 把两个区域中的所有存活对象都转移到完全独立的空间中,也就是第二块Survivor中,这样就可以留出一块完全空着的Eden和Survivor了,下次GC的时候再重复这个流程
  3. 两个survivor的情况

    如果存在两个survivor区,当Eden区满的时候,发生minor gc,有存活对象,将对象转移到Survivor0中,当下次再发生minor gc的时候,将Eden区和S0区的存活对象复制到S1中(这种复制算法可以保证S1中来自Eden和S0中对象的地址是连续的),清空Eden区和S0的空间,然后交换S0和S1的角色,之后发生minor gc时,循环往复。直到存活对象old enough,升入老年代。
    这种情况下我们可以保证始终有一个Survivor的空间是没有碎片的,而另外一个Survivor是空着的。

参考链接1
参考链接2

日记本
Web note ad 1