深入理解JVM——(三)为什么JVM新生代需要两个Survivor区

354 阅读2分钟

经过了JVM区域的学习,我们知道在堆中新生代具有一个Eden区和两个Survivor区,这里就有疑问了,为什么需要Survivor区和为什么需要两个Survivor区?带着疑问我们思考一下。

一、为什么需要Survivor区?

带着这个问题,我们假设一下,如果没有Survivor区,新生代只有Eden区。

当Eden区装满后,Minor GC进行垃圾回收,幸存的对象会直接放入老年代,可以想到,要不了多久老年代就会装满,便会进行Major GC且连带Minor GC也就是Full GC,每次Full GC都会消耗大量的时间。也许你会问,执行时间长有什么问题?频发的Full GC会消耗大量的时间,会影响程序的执行与响应速度,导致连接超时等等一系列问题。所以,会出现老年代频发Full GC而严重影响效率的问题

那么,如果不依靠Survivor区,我们应该如何解决老年代频发Full GC的问题呢?

方案 优点 缺点
增大老年代内存空间 更多对象才会填满老年代,降低Full GC频率 每次GC消耗更长的时间
减小老年代内存空间 Full GC执行时间减少 Full GC频率增加

由此可见,没有Survivor区无法从根本解决问题。

结论:Survivor具有预筛选保证,只有对象到一定岁数才会送往老年代,Survivor区可以减少被送到老年代的对象,进而减少Full GC发生。

二、为什么需要两个Survivor区?

可以知道,新生代使用复制回收算法,我们设想一下只有一个Survivor区会发生什么情况。

当Eden区填满后,Minor GC进行垃圾回收,幸存的对象会移动到Survivor区,这样循环往复。此时,Survivor区被装满了,也会进行Minor GC,将一些对象kill掉,幸存的对象只能保存在原来的位置,这样就会出现大量的内存碎片(被占用内存不连续)

内存碎片化是严重影响性能的,可以设想当有一个稍大一点的对象从Eden区存活转入Survivor区,发现空闲内存断断续续,没有他能落脚的地方,就只能直接存到老年代了,如此反复,老年代会出现我们第一部分的问题。打个比方:我们出去郊游,一些吃的罐头,玩的玩具随便放在包里,最后发现最主要的折叠帐篷放不进去了,只好手拿着到处溜达,非常不方便且影响心情。

最后,如果有两个Survivor区,便可以保证一个为空,另一个是非空且无碎片保存的