新生代Eden区、两个Survivor区及老年代的关系

探讨JVM年轻代中Eden区与Survivor区8:1:1比例的原理,解析年轻代分区如何减轻老年代负担,减少内存碎片,提高GC效率。

偶然想起JVM年轻代中Eden区和两个Survivor的比例,就想根据自己的理解和大家探讨一下为什么要配成8 :1 :1的比例。

一、JVM堆分代

1、JVM堆被分为了年轻代和老年代。年轻代的GC过程称为Yong GC,速度快较频繁。老年代的GC过程称为Full GC,速度较慢应该尽量避免。

2、对象被创建后,除了少部分大对象会在老年代分配内存外,大部分的对象首先都是在年轻代进行内存分配,而且大部分的对象都是“朝生夕死”,很快就会被年轻代的Yong GC回收掉。

3、老年代的内存空间一般会比年轻代的内存空间大,能存放的对象多,老年代的空间不足后会进行Full GC操作,比Yong GC耗时,所以应尽量避免频繁的Full GC操作。

二、年轻代的分区

1、年轻代中分为一个Eden区和两个Surviver区,比例为8:1:1,两个Surviver区分别称为“From”区和“To”区。对象在Eden区创建,经过一次Yong GC后,还存活的对象将会被复制到Surviver区的“From”区,此时“To”区是空的。到了下一次GC的时候,Eden区还存活的对象会复制到Surviver区的“To”区,而“Form”区的对象有两个去处,“From”区的对象会根据经过的GC次数计算年龄,如果年龄到达了阈值(默认15),则会被移动到老年代中,否则就复制到“To”区,此时“From”区变成了空的,然后“From”区和“To”区进行角色互换,到下一次进行GC时,还是有一块空的“To”区,用来存放从eden区和“From”区移动过来的对象。

2、那这种分区有什么好处呢?

a、在年轻代新增Surviver区,有利于减轻老年代的负担,尽可能的让大部分对象在年轻代通过较高效的Yong GC回收掉,不至于老年代里存放的对象过多导致内存不足而进行频繁的Full GC操作。

b、这种分区有利于减少内存碎片的产生。

首先我们来看看,如果年轻代只分为Eden区和Surviver区两个区域并且比例是8:2的时候,内存的回收和分配情况会怎么样。第一次Yong GC后,Eden区还存活的对象移动到Surviver区,Surviver区还存活的对象保留在Surviver区,而这些对象的内存是不连续的,Surviver区里就会产生很多内存碎片,这就会导致有些大对象要移动到Surviver区的时候,没有足够的连续内存进行分配,而不得不移动到老年代中,增加老年代的负担,降低效率。

然后我们看看Eden区和Surviver区的比例是8:1:1时会有什么样的效果。第一次Yong GC后,Eden区还存活的对象复制到Surviver区的“To”区,“From”区还存活的对象也复制到“To”区,再清空Eden区和From区,这样就等于“From”区完全是空的了,而“To”区也不会有内存碎片产生,等到第二次Yong GC时,“From”区和“To”区角色互换,很好的解决了内存碎片的问题。

如下图所示:

有人要说为什么一定是8:1:1的比例呢,这大概是前辈们实践出来的最佳比例吧~~

 

### Java 堆内存中 S0、S1、Eden 以及新生代老年别 #### 1. Eden Eden 新生代的一部分,主要用于分配新创建的对象。大多数情况下,对象会在 Eden 被首次分配内存。由于大部分对象的生命周期较短,通常在一次垃圾回收后会被清理掉。当 Eden 满时,会触发 Minor GC 来清理无用对象并将幸存下来的对象移动到 Survivor 之一[^3]。 #### 2. Survivor (S0 和 S1) Survivor 也被划分为两个部分:S0(Survivor 0)和 S1(Survivor 1)。这两个域的作用是对称的,在每次 Minor GC 后互换角色。复制算法用于将 Eden 中存活的对象复制到其中一个 Survivor 域(假设当前为 S0),而原本存在于另一个 Survivor 域(即 S1)中的存活对象也会被复制过来。这样做的好处是不会产生内存碎片[^3]。 - **S0 和 S1 的切换**:每经历一次 Minor GC,S0 和 S1 就会交换职责。也就是说,本轮作为目标域的 S0 下轮将成为源域,反之亦然。 - **分年龄**:每当一个对象成功经过一次 Minor GC 并转移到 Survivor 时,其“分年龄”加一。一旦某个对象达到预设阈值,则它会被晋升至老年[^2]。 #### 3. 新生代 新生代Eden两个 Survivor 共同构成,主要用来存放短期存在的对象。根据统计规律表明大约98%的对象在其诞生后的很短时间内就会消亡,因此采用复制算法可以有效地减少内存碎片化问题[^4]。 - 默认比例:新生代默认占堆内存的 1/3,其中 Eden新生代的 8/10,S0 和 S1 各占 1/10[^2]。 #### 4. 老年 老年占据堆内存的主要部分,默认占堆内存的 2/3,专门存储那些经历过多次 Minor GC 仍然存活下来的大对象或者是长期驻留的对象。相比起频繁发生的 Minor GC 而言,Full GC 较少见但也更耗时,因为它涉及整个堆包括新生代老年的整体扫描及整理工作。 - **大对象直接进入老年**:当新创建的对象过大以至于无法在新生代找到足够的连续内存时,该对象会直接在老年中创建[^1]。 ```java // 示例码展示如何查看JVM内存使用情况 public class MemoryUsageExample { public static void main(String[] args) { Runtime runtime = Runtime.getRuntime(); long maxMemory = runtime.maxMemory(); // JVM最大可用内存 long totalMemory = runtime.totalMemory(); // 当前JVM占用的总物理内存 long freeMemory = runtime.freeMemory(); // 可供程序使用的剩余内存 System.out.println("Max memory: " + (maxMemory / (double)(1024 * 1024)) + " MB"); System.out.println("Total memory: " + (totalMemory / (double)(1024 * 1024)) + " MB"); System.out.println("Free memory: " + (freeMemory / (double)(1024 * 1024)) + " MB"); Object obj = new Object(); // 创建一个小对象放入新生代 } } ``` ---
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值