zl程序教程

您现在的位置是:首页 >  IT要闻

当前栏目

面试官:为什么新生代内存需要有两个Survivor区?

2023-03-15 22:01:46 时间

1 、Survivor存在的意义

先不去想为什么有两个Survivor区,先设想下Survivor区的意义在哪里?

如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。这样老年代内存很快就被用完,触发Major GC。由于老年代的内存空间远大于新生代,所以进行一次Full GC消耗的时间比Minor GC长得多,这样就会导致系统执行缓慢卡顿,响应速度过慢,用户体验十分不好,更不要说某些连接会因为超时发生连接错误了。

那我们来想想在没有Survivor的情况下,有没有什么解决办法,可以避免上述情况:

  • 增加老年代内存
    • 好处是能够承担更多存活对象,降低GC频次
    • 缺点也是显而易见的,空间越大,发生GC所需要的时间更长
  • 减少老年代内存
    • 优点就是GC所需要的时间减少
    • 缺点就是GC频次增加

显而易见,没有Survivor的话,上述两种解决方案都不能从根本上解决问题。

所以可以得到第一条结论:Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历16次Minor GC还能在新生代中存活的对象,才会被送到老年代。

2 、为什么要设置两个Survivor

设置两个Survivor区最大的好处就是解决了碎片化

为什么一个Survivor区不行?假设现在只有一个survivor区,我们来模拟一下流程:

Eden满了,触发一次Minor GC,Eden中的存活对象就会被移动到Survivor区。继续循环下去,下一次Eden满了的时候进行Minor GC,Eden和Survivor各有一些存活对象,如果此时把Eden区的存活对象硬放到Survivor区,很明显这两部分对象所占有的内存是不连续的,也就导致了内存碎片化,严重影响系统性能。

顺理成章的,应该建立两块Survivor区,刚刚新建的对象在Eden中,经历一次Minor GC,Eden中的存活对象就会被移动到第一块survivor space S0,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor space S1(这个过程非常重要,因为这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间,避免了碎片化的发生)。

S0和Eden被清空,然后下一轮S0与S1交换角色,如此循环往复。如果对象的复制次数达到16次,该对象就会被送到老年代中。

上述机制最大的好处就是,整个过程中,永远有一个survivor space是空的,另一个非空的survivor space无碎片。

最后打个广告,如果你觉得这篇文章对你有帮助,可以关注我的技术公众号【CodingCode】。你的关注和转发是对我最大的支持,O(∩_∩)O。