JVM 新生代为何需要两个 Survivor 空间?

本文探讨了虚拟机中新生代内存布局的原因,解释了为何采用两个Survivor空间而非一个或没有,通过对比不同配置下的Minor GC触发情况,揭示了两个Survivor空间的优势。

转载http://dsxwjhf.iteye.com/blog/2201687



我们知道,目前主流的虚拟机实现都采用了分代收集的思想,把整个堆区划分为新生代和老年代;新生代又被划分成 Eden 空间、 From Survivor 和 To Survivor 三块区域。 

看书的时候有个疑问,为什么非得是两个 Survivor 空间呢?要回答这个问题,其实等价于:为什么不是0个或1个 Survivor 空间?为什么2个 Survivor 空间可以达到要求? 

为什么不是0个 Survivor 空间? 

这个问题等价于:为什么需要 Survivor 空间。我们看看如果没有 Survivor 空间的话,垃圾收集将会怎样进行:一遍新生代 gc 过后,不管三七二十一,活着的对象全部进入老年代,即便它在接下来的几次 gc 过程中极有可能被回收掉。这样的话老年代很快被填满, Full GC 的频率大大增加。我们知道,老年代一般都会被规划成比新生代大很多,对它进行垃圾收集会消耗比较长的时间;如果收集的频率又很快的话,那就更糟糕了。基于这种考虑,虚拟机引进了“幸存区”的概念:如果对象在某次新生代 gc 之后任然存活,让它暂时进入幸存区;以后每熬过一次 gc ,让对象的年龄+1,直到其年龄达到某个设定的值(比如15岁), JVM 认为它很有可能是个“老不死的”对象,再呆在幸存区没有必要(而且老是在两个幸存区之间反复地复制也需要消耗资源),才会把它转移到老年代。 

总之,设置 Survivor 空间的目的是让那些中等寿命的对象尽量在 Minor GC 时被干掉,最终在总体上减少虚拟机的垃圾收集过程对用户程序的影响。 

为什么不是1个 Survivor 空间? 

回答这个问题有一个前提,就是新生代一般都采用复制算法进行垃圾收集。原始的复制算法是把一块内存一分为二, gc 时把存活的对象从一块空间(From space)复制到另外一块空间(To space),再把原先的那块内存(From space)清理干净,最后调换 From space 和 To space 的逻辑角色(这样下一次 gc 的时候还可以按这样的方式进行)。 

我们知道,在 HotSpot 虚拟机里, Eden 空间和 Survivor 空间默认的比例是 8:1 。我们来看看在只有一个 Survivor 空间的情况下,这个 8:1 会有什么问题。此处为了方便说明,我们假设新生代一共为 9 MB 。对象优先在 Eden 区分配,当 Eden 空间满 8 MB 时,触发第一次 Minor GC 。比如说有 0.5 MB 的对象存活,那这 0.5 MB 的对象将由 Eden 区向 Survivor 区复制。这次 Minor GC 过后, Eden 区被清理干净, Survivor 区被占用了 0.5 MB ,还剩 0.5 MB 。到这里一切都很美好,但问题马上就来了:从现在开始所有对象将会在这剩下的 0.5 MB 的空间上被分配,很快就会发现空间不足,于是只好触发下一次 Minor GC 。可以看出在这种情况下,当 Survivor 空间作为对象“出生地”的时候,很容易触发 Minor GC ,这种 8:1 的不对称分配不但没能在总体上降低 Minor GC 的频率,还会把 gc 的时间间隔搞得很不平均。把 Eden : Survivor 设成 1 : 1 也一样,每当对象总大小满 5 MB 的时候都必须触发一次 Minor GC ,唯一的变化是 gc 的时间间隔相对平均了。 

上面的论述都是以“新生代使用复制算法”这个既定事实作为前提来讨论的。如果不是这样,比如说新生代采用“标记-清除”或者“标记-整理”算法来实现幸存对象的移动,好像确实是只需要一个 Survivor 就够了。至于主流的虚拟机实现为什么不考虑采用这种方式,我也不是很清楚,或许有实现难度、内存碎片或者执行效率方面的考虑吧。 

为什么2个 Survivor 空间可以达到要求? 

问题很清楚了,无论 Eden 和 Survivor 的比例怎么设置,在只有一个 Survivor 的情况下,总体上看在新生代空间满一半的时候就会触发一次 Minor GC 。那有没有提升的空间呢?比如说永远在新生代空间满 80% 的时候才触发 Minor GC ? 

事实上是可以做到的:我们可以设两个 Survivor 空间( From Survivor 和 To Survivor )。比如,我们把 Eden : From Survivor : To Survivor 空间大小设成 8 : 1 : 1 ,对象总是在 Eden 区出生, From Survivor 保存当前的幸存对象, To Survivor 为空。一次 gc 发生后: 
1)Eden 区活着的对象 + From Survivor 存储的对象被复制到 To Survivor ; 
2) 清空 Eden 和 From Survivor ; 
3) 颠倒 From Survivor 和 To Survivor 的逻辑关系: From 变 To , To 变 From 。 

可以看出,只有在 Eden 空间快满的时候才会触发 Minor GC 。而 Eden 空间占新生代的绝大部分,所以 Minor GC 的频率得以降低。当然,使用两个 Survivor 这种方式我们也付出了一定的代价,如 10% 的空间浪费、复制对象的开销等。

<think>嗯,用户想知道JVM新生代的分结构,特别是Eden和Survivor域。首先,我需要回忆一下JVM的内存管理部分。根据之前的引用资料,新生代分为Eden和两个Survivor,也就是S0和S1,或者From和To。那为什么要这样分呢?可能和垃圾回收算法有关,尤其是复制算法。 用户的问题比较直接,就是问分结构包括哪些域。根据引用3和5,新生代包括一个Eden两个Survivor。需要明确每个域的作用。比如,Eden是对象初次分配的地方,Survivor用于存放经过垃圾回收后存活的对象。 可能用户还不太清楚具体的工作流程,比如Minor GC发生时,Eden存活的对象会被复制到Survivor,然后Survivor之间会有交换。这里需要解释清楚复制算法的作用,减少内存碎片,提高GC效率。 另外,用户可能想知道为什么是两个Survivor而不是一个。根据引用2,复制算法需要一块空闲域来存放存活对象,两个Survivor轮流承担这个角色,确保每次回收时有一个是空的。这样可以有效管理内存,避免碎片问题。 还要注意引用来源,比如引用1提到新生代用于生命周期短的对象,引用5说明Eden是主要分配域,Survivor存放存活对象,多次存活后晋升到老年代。需要把这些信息整合起来,结构清晰地呈现。 可能用户的实际应用场景是优化内存配置或调优GC性能,因此需要解释每个分作用和设计原因。确保回答准确,并引用相关参考资料来支持每个观点。最后,生成的相关问题要围绕GC机制、参数配置和晋升机制展开,帮助用户深入理解。</think>### JVM新生代的分结构解析 JVM新生代(Young Generation)主要分为 **Eden** 和 **两个Survivor(S0和S1,或From和To)**。以下是各域的详细说明: 1. **Eden** - **功能**:新创建的对象首先分配到Eden,大部分对象的生命周期极短,可能在一次垃圾回收(Minor GC)后就被回收[^5]。 - **设计原因**:集中管理新对象的分配,避免频繁扫描老年代,提升内存分配效率[^3][^4]。 2. **Survivor** - **功能**:存放从Eden经过一次Minor GC后存活的对象。两个Survivor(S0和S1)通过**复制算法**协作: - 每次Minor GC时,存活对象从Eden和当前使用的Survivor(From)复制到另一个SurvivorTo),同时年龄计数器加1。 - 多次存活(默认15次)的对象会被晋升到老年代[^2]。 - **设计原因**: - 通过复制算法减少内存碎片,提高垃圾回收效率。 - 两个Survivor交替使用,确保每次Minor GC后总有一个完全空闲的域接收存活对象[^2][^4]。 --- #### 新生代的工作流程 1. 对象优先分配到Eden。 2. Eden满时触发Minor GC,存活对象移动到Survivor的From空间。 3. 后续Minor GC时,Eden和From空间的存活对象复制到To空间,同时年龄计数器递增。 4. 年龄达到阈值的对象晋升到老年代,Survivor角色(From/To)交换。 --- #### 分设计的优势 - **高效内存管理**:通过分离短生命周期和长生命周期对象,减少老年代的GC压力[^1][^4]。 - **减少碎片化**:复制算法通过移动存活对象,避免内存碎片问题[^2]。 - **动态对象年龄判定**:根据Survivor的使用情况动态调整晋升阈值,优化内存利用率。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值