在学习JVM GC的过程中,突然想到了一个问题,为什么新生代中有两个Survivor区,并且Eden区和两个survivor的比例为8:1:1?难道改成一个Survivor区,比例调整为9:1不香吗?
为什么JVM新生代需要两个Survivor区?
JVM需要两个Survivor区其实是基于新生代的复制收集算法。
复制收集算法
当Eden满了或者进入Eden的对象大于Eden剩余空间时,会进行GC,将Eden和Survivor From中的存活的对象拷贝到Survivor To 中,并且清除其余对象同时反转Survivor From 和Survivor To, 使To变From,From变To。
如果只有一个Survivor会发生什么?
如果只存在一个Survivor,Eden满了之后将数据清除,存活的对象转移至Survivor,好像没有问题。但是第二次GC,根据复制收集算法,要将Eden和Survivor存活的对象复制到一个Survivor中,并没有第二个Survivor来存放这些存活的对象。那就会有问题,只能Survivor中的数据不清理,只把Eden中存活的对象放入Survivor中,这会导致Survivor中空间急剧升高,频繁GC,同时Survivor中很多不必要的对象无法清理,继续占用空间。
如果做一些改良会怎样?
假如我们在Eden满之后把存活对象放入Survivor中,同时可以把Survivor中不需要的对象给清理了,是不是一切豁然开朗了呢?这种情况下少了一个Survivor,内存使用率不再是只有90%,达到了100%,一切看起来那么美好。但是新的问题他又来了:如果只有一个Survivor,清理Survivor的过程中,会导致一些内存的碎片化,每次GC都会产生碎片化的内存,导致内存地址的不连续。碎片化带来的风险是极大的,严重影响JAVA程序的性能。堆空间被散布的对象占据不连续的内存,最直接的结果就是,堆中没有足够大的连续内存空间,会导致Eden一些较大的存活对象,由于Survivor空间的不够只能进入老年代。
综上所诉,大家应该对为什么JVM新生代需要两个Survivor区有了足够的认知。