【JVM三】新生代垃圾回收

JVM将堆空间划分为新生代和老年代,如此花费是为了更高效的进行垃圾回收。

  • 简化创建对象的内存分配,新创建的对象都会放到新生代
  • 针对新生代和老年代的特点,使用不同的垃圾回收策略。

面向对象编程中的对象,广泛的研究表明,对象大多是朝生夕死,并且已经在JVM上存活较长时间的对象很少引用新生的对象,基于这两方面的原因,把新生对象放到新生代,GC可以更快查找可以被回收的对象

 

新生代的区域划分

 

Sun/Oracle的HotSpot JVM将新生代做了细分,HotSpot将新生代划分为3个区域,较大的区域称为"Eden",两个较小的幸存者空间(survisor spaces),这两个幸存者空间一个称为From,另一个称为To。一轮GC过程中,Eden活下来的对象将被移动到幸存者空间,这些对象将在幸存者空间呆上一段时间(呆在这个阶段期间,这些对象可能要经历几次GC),如果几次GC后,这写位于幸存者空间的对象依然存活,那么它们将被移动到老年代。因此,幸存者空间就是给进入新生代的对象更多点呆在新生代的时间。每次GC时,Eden和幸存者空间都要被扫描以确定哪些对象要被回收。

 

新生代垃圾回收的过程

基于新生代中的对象在经历过一次GC后,大多数对象都会被回收的假设,新生代垃圾会采用复制的策略:

1. 在GC刚开始的时候,Survior的To空间是空的,对象只能存在于Eden或者From。

2. 随着GC的进行,

    2.1 Eden空间依然被引用的对象将被移动到To空间。

    2.2 From空间,这个空间中依然被引用的对象的处理依赖于它们的存活了的多少时间。如果它们的存活周期没有达到某个阀值(tenuring threshold,表示经历了几次GC依然存活),那 么它们也要被移动到To,否则它们将被移动到老年代。

3. 当这个copy的过程结束后,Eden和From空间中的对象是可被回收了(新生代所有存活下来的对象要么去了To,要么去了老年代)。在Eden,From向To空间移动的过程中,To空间有可能满了,那么剩下的对象,将直接移动到老年代。

4. 最后一步,From和To交换角色,因此在下一轮GC开始时,To是空的,而From则包含了所有新生代上轮GC时存活下来的对象。

 

下图所示是新生代GC开始时的状态以及GC结束时的状态

 

 

 新生代GC过程总结

 

刚创建的对象在放在Eden,然后在新生代GC时,可能被移动到To空间。如果对象在几轮年轻代垃圾回收之后依然存活,那么它最终会被移动到老年代。对老年代的垃圾回收需要更大的代价,这需要更高效的GC算法(老年代不能使用简单的复制,因为没有空间可以复制了)。因此,新生代的堆空间容量是非常重要的,如果新生代空间太小,那么新生代的对象很快就会被移动到老年代(老年代垃圾回收的代价要远远超过新生代);反之,如果新生代过大,那对于长时间存活而最后到达老年代的对象,就会导致很多不必要的复制(每轮GC都要复制)。一次需要在新生代空间大小上取一个合适的值,以适应特定的应用。JVM提供了一系列的选项用于对新生代的容量调整。

 

 

新生代相关的JVM选项

 

 -XX:NewSize and -XX:MaxNewSize

 

-Xms和-Xmx分别表示堆内存的最小值和最大值,--XX:NewSize和-XX:MaxNewSize分别表示新生代的最小值和最大值。需要注意的是,--XX:NewSize和-XX:MaxNewSize设置的新生代的容量,新生代设置的越大,那么老年代则越小。实际中,基于稳定性考虑,新生代的大小应该小于老年代的堆大小,因为在最糟糕的情况下,GC有可能将新生代所有的对象移动到老年代,因此,新生代堆的大小上限是-Xmx/2。
基于性能的考虑,新生代的初始大小设置为--XX:NewSize,这个值的设置也是一个参考值。

 

 -XX:NewRatio

 

 通过-XX:NewRation这个选项来显式的指定新生代和老年代的大小比例。通过这种相对大小的方式,可以让JVM在运行时由于动态调整堆大小时,动态的调整新生代的大小。-XX:NewRatio=3表示老年代是新生代的3倍,即新生代占堆空间的1/4,而老年大则占堆空间的3/4.

 

如果既设置了-XXNewSize,-XX:MaxNewSize,也设置了-XX:NewRatio,那么JVM首先尝试将新生代的大小按照新老比例进行设置(-XX:NewRatio),但是最小值不能低于-XXNewSize,最大值不能超过--XX:MaxNewSize

 

 


 -XX:SurvivorRatio

 

-XX:SurvivorRatio用来设置在新生代内部,Eden区与Survior区的大小比例关系。比如-XX:SurvivorRatio=10表示Eden区域的大小时Survivor的From/To区域的10倍,也就是说,Eden占新生代的10/12,From和To各占1/12。

 

-XX:+PrintTenuringDistribution

 

使用-XX:+PrintTenuringDistribution这个选项是让JVM在每次新生代GC时,打印出survivor区域的对象的存活周期,比如:

 

Desired survivor size 75497472 bytes, new threshold 15 (max 15)
- age   1:   19321624 bytes,   19321624 total
- age   2:      79376 bytes,   19401000 total
- age   3:    2904256 bytes,   22305256 total

 

第一行信息是"To"空间的大小约75MB。新生代经历15次GC依然存活的,将从survivor区域移动到老年代。

 

下面的几行则显示了经历了几次新生代GC的对象的空间利用情况。例子中的数目表明:大约19M的对象经历了一次GC,大约79KB经历了两次GC,大约3MB经历了3次GC。在每行的最后,是在这个age范围内所包含的所有对象占用的空间,比如对个age 2,它包含的总数包括age 1对象占用的空间加age 2对象占用的空间。因此,"total"这个值意味着"To"空间当前大概包含22M对象数据。因为”To“空间的可用空间是75MB并且threshold是15,因此,当前没有对象需要移动到老年代。

 

再来看一下新一轮GC的情况:

 

Desired survivor size 75497472 bytes, new threshold 2 (max 15)
- age   1:   68407384 bytes,   68407384 total
- age   2:   12494576 bytes,   80901960 total
- age   3:      79376 bytes,   80981336 total
- age   4:    2904256 bytes,   83885592 total

 

比较两组数据,可以看到如下信息

1. 可见原来的age 1变为后面的age 2, 原来的age 2变为后面的age 3, 原来的age 3变为后面的age 4

2. 原来age1大概有19M,而后面的age2只有12M,也就说,这轮GC,有大概7M的内容被回收。

3. ,新一轮GC增加了大概68M的新增对象进入age 1。也就说,在这一轮GC中,JVM从Eden区移动了大概68M的数据进入To空间

 

4.在上面的示例中,To空间已经达到将近84M,超过75MB。因此,JVM把tenuring threshold从15降低到2,因此,接下来新一轮GC,那么To空间的对象,要么生命到期而被回收,要么进入老年代。

 

注:tenuring threshold参数的含义是控制对象经历多少次Minor GC才从新生代晋升到老年代代

 

-XX:InitialTenuringThreshold, -XX:MaxTenuringThreshold and -XX:TargetSurvivorRatio

 

【TBD:这段需要重写】

-XX:+PrintTenuringDistribution这个选项的输出结果可以由多个选项进行调整。通过-XX:InitialTenuringThreshold 和-XX:MaxTenuringThreshold可以设置tenuring threshold的初始值和最大值。并且,我们也可以通过-XX:TargetSurvivorRatio来在新生代GC结束时,用于指定"To"的目标使用率。比如同时设置如下两个选项,

-XX:MaxTenuringThreshold=10 -XX:TargetSurvivorRatio=90设置了tenuring threshold的上限是10,并且指定了"To"空间的目标使用率是90%。如下两个场景:

1.如果-XX:+PrintTenuringDistribution显示的结果表示它们在最后达到最大tenuring threshold前经历了很多次GC,通常意味着-XX:MaxTenuringThreshold的设置偏大。

2.

 

 

The tuning knobs shown in the output of -XX:+PrintTenuringDistribution can be adjusted by various flags. With -XX:InitialTenuringThreshold and -XX:MaxTenuringThreshold we can set the initial and maximum value of the tenuring threshold, respectively. Additionally, we can use -XX:TargetSurvivorRatio to specify the target utilization (in percent) of “To” at the end of a young generation GC. For example, the combination -XX:MaxTenuringThreshold=10 -XX:TargetSurvivorRatio=90 sets an upper bound of 10 for the tenuring threshold and a target utilization of 90 percent for the “To” survivor space.

While there are different approaches to use these flags to tune young generation behavior, no general guideline is available. We restrict ourselves to two cases that are pretty clear:

  • If the tenuring distribution shows that many objects just grow older and older before finally reaching the maximum tenuring threshold, this indicates that the value of -XX:MaxTenuringThreshold may be too large.
  • If the value of -XX:MaxTenuringThreshold is larger than 1 but most objects never reach an age larger than 1, we should take a look at the target utilization of “To”. Should the target utilization never be reached, then we know that all young objects get collected by the GC, which is exactly what we want. However, if the target utilization is frequently reached, then at least some of the objects beyond age 1 have been moved into the old generation, and maybe prematurely so. In this case, we can try to tune the survivor spaces by increasing their size or target utilization.
 
 
 
 
 
 
 
 
 
 
 
 
 

 

 

 

 本文参考:https://blog.codecentric.de/en/2012/08/useful-jvm-flags-part-5-young-generation-garbage-collection/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值