JVM 新生代老年代

本文深入探讨了Java垃圾回收机制中的年轻代分区原理及其优化策略。解释了为什么需要年轻代,详细介绍了年轻代中的垃圾回收过程,包括Eden区与Survivor区的角色转换,以及对象从年轻代晋升到老年代的过程。

1.为什么会有年轻代

我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能。你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用,这样就会对堆的所有区域进行扫描。而我们的很多对象都是朝生夕死的,如果分代的话,我们把新创建的对象放到某一地方,当GC的时候先把这块存“朝生夕死”对象的区域进行回收,这样就会腾出很大的空间出来。

 

2.年轻代中的GC

    HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫from和to)。默认比例为8:1,为啥默认会是这个比例,接下来我们会聊到。一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中。

因为年轻代中的对象基本都是朝生夕死的(80%以上),所以在年轻代的垃圾回收算法使用的是复制算法,复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。

在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。

young_gc

 

3.一个对象的这一辈子

我是一个普通的Java对象,我出生在Eden区,在Eden区我还看到和我长的很像的小兄弟,我们在Eden区中玩了挺长时间。有一天Eden区中的人实在是太多了,我就被迫去了Survivor区的“From”区,自从去了Survivor区,我就开始漂了,有时候在Survivor的“From”区,有时候在Survivor的“To”区,居无定所。直到我18岁的时候,爸爸说我成人了,该去社会上闯闯了。于是我就去了年老代那边,年老代里,人很多,并且年龄都挺大的,我在这里也认识了很多人。在年老代里,我生活了20年(每次GC加一岁),然后被回收。

4.有关年轻代的JVM参数

1)-XX:NewSize和-XX:MaxNewSize

用于设置年轻代的大小,建议设为整个堆大小的1/3或者1/4,两个值设为一样大。

2)-XX:SurvivorRatio

用于设置Eden和其中一个Survivor的比值,这个值也比较重要。

3)-XX:+PrintTenuringDistribution

这个参数用于显示每次Minor GC时Survivor区中各个年龄段的对象的大小。

4).-XX:InitialTenuringThreshol和-XX:MaxTenuringThreshold

用于设置晋升到老年代的对象年龄的最小值和最大值,每个对象在坚持过一次Minor GC之后,年龄就加1。

### JVM新生代年代的比例配置及默认值 #### 默认比例 在 Java 虚拟机 (JVM) 的堆内存分配中,默认情况下,新生代 (Young Generation) 和年代 (Old Generation, 或 Tenured Generation) 的比例为 **1:2**。这意味着整个堆空间会被划分为三部分: - 新生代占据总堆的三分之一。 - 年代占据总堆的三分之二。 这种划分方式适用于大多数应用场景,但在某些特定场景下可能需要调整该比例以优化性能[^1]。 #### 配置方法 可以通过以下几种方式进行新生代年代的比例配置: 1. **使用 `-XX:NewRatio` 参数** - 此参数用于设置新生代年代之间的比例关系。例如,如果指定 `-XX:NewRatio=3`,则表示年代的空间是新生代的 3 倍,即新生代占四分之一,而年代占剩余的四分之三[^3]。 2. **使用 `-Xmn` 参数** - 可以通过直接设定新生代的具体大小来间接影响其与年代的比例。例如,`-Xmn256m` 表示将新生代固定为 256MB 大小。此时,年代的大小由总的堆大小减去新生代大小决定。 3. **综合配置示例** 下面是一个完整的配置例子: ```bash java -Xms1024m -Xmx1024m -Xmn256m -XX:NewRatio=3 MyApplication ``` 这里的含义如下: - `-Xms1024m`: 初始堆大小设为 1GB。 - `-Xmx1024m`: 最大堆大小也设为 1GB。 - `-Xmn256m`: 将新生代大小显式设置为 256MB。 - `-XX:NewRatio=3`: 如果未通过 `-Xmn` 显式定义,则按照此比例计算新生代年代大小。 #### 注意事项 当调整新生代年代的比例时需要注意以下几点: - 不同的应用程序有不同的垃圾收集模式需求。对于短生命周期的对象较多的情况,可以适当增加新生代的比例;而对于长生命周期对象较多的情况,则应减少新生代占比并增大年代份额。 - 若新生代过小可能导致频繁发生 Minor GC,从而降低应用程序吞吐量;反之,若新生代过大可能会延长 Major GC 时间[^2]。 ```java // 示例代码展示如何启动带有自定义堆选项的Java进程 public class HeapConfigExample { public static void main(String[] args) { System.out.println("Heap Configuration Example"); Runtime runtime = Runtime.getRuntime(); long maxMemory = runtime.maxMemory(); // 获取最大可用堆内存 long totalMemory = runtime.totalMemory(); // 当前已分配给JVM的堆内存 System.out.printf("Max Memory: %d MB%n", maxMemory / (1024 * 1024)); System.out.printf("Total Memory: %d MB%n", totalMemory / (1024 * 1024)); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值