原文链接  作者: PATRICK PESCHLOW ;译者:严亮

本部分,我们将关注堆(heap) 中一个主要区域,新生代(young generation)。首先我们会讨论为什么调整新生代的参数会对应用的性能如此重要,接着我们将学习新生代相关的JVM参数。

单纯从JVM的功能考虑,并不需要新生代,完全可以针对整个堆进行操作。新生代存在的唯一理由是优化垃圾回收(GC)的性能。更具体说,把堆划分为新生代和老年代有2个好处:简化了新对象的分配(只在新生代分配内存),可以更有效的清除不再需要的对象(即死对象)(新生代和老年代使用不同的GC算法)

通过广泛研究面向对象实现的应用,发现一个共同特点:很多对象的生存时间都很短。同时研究发现,新生对象很少引用生存时间长的对象。结合这2个特点,很明显 GC 会频繁访问新生对象,例如在堆中一个单独的区域,称之为新生代。在新生代中,GC可以快速标记回收”死对象”,而不需要扫描整个Heap中的存活一段时间的”老对象”。

SUN/Oracle 的HotSpot JVM 又把新生代进一步划分为3个区域:一个相对大点的区域,称为”伊甸园区(Eden)”;两个相对小点的区域称为”From 幸存区(survivor)”和”To 幸存区(survivor)”。按照规定,新对象会首先分配在 Eden 中(如果新对象过大,会直接分配在老年代中)。在GC中,Eden 中的对象会被移动到survivor中,直至对象满足一定的年纪(定义为熬过GC的次数),会被移动到老年代。

基于大多数新生对象都会在GC中被收回的假设。新生代的GC 使用复制算法。在GC前To 幸存区(survivor)保持清空,对象保存在 Eden 和 From 幸存区(survivor)中,GC运行时,Eden中的幸存对象被复制到 To 幸存区(survivor)。针对 From 幸存区(survivor)中的幸存对象,会考虑对象年龄,如果年龄没达到阀值(tenuring threshold),对象会被复制到To 幸存区(survivor)。如果达到阀值对象被复制到老年代。复制阶段完成后,Eden 和From 幸存区中只保存死对象,可以视为清空。如果在复制过程中To 幸存区被填满了,剩余的对象会被复制到老年代中。最后 From 幸存区和 To幸存区会调换下名字,在下次GC时,To 幸存区会成为From 幸存区。


https://blog.codecentric.de/files/2011/08/young_gc.png
上图演示GC过程,黄色表示死对象,绿色表示剩余空间,红色表示幸存对象

总结一下,对象一般出生在Eden区,年轻代GC过程中,对象在2个幸存区之间移动,如果对象存活到适当的年龄,会被移动到老年代。当对象在老年代死亡时,就需要更高级别的GC,更重量级的GC算法(复制算法不适用于老年代,因为没有多余的空间用于复制)

现在应该能理解为什么新生代大小非常重要了(译者,有另外一种说法:新生代大小并不重要,影响GC的因素主要是幸存对象的数量),如果新生代过小,会导致新生对象很快就晋升到老年代中,在老年代中对象很难被回收。如果新生代过大,会发生过多的复制过程。我们需要找到一个合适大小,不幸的是,要想获得一个合适的大小,只能通过不断的测试调优。这就需要JVM参数了

-XX:NewSize and -XX:MaxNewSize
就像可以通过参数(-Xms and -Xmx) 指定堆大小一样,可以通过参数指定新生代大小。设置 XX:MaxNewSize 参数时,应该考虑到新生代只是整个堆的一部分,新生代设置的越大,老年代区域就会减少。一般不允许新生代比老年代还大,因为要考虑GC时最坏情况,所有对象都晋升到老年代。(译者:会发生OOM错误) -XX:MaxNewSize 最大可以设置为-Xmx/2 .

考虑性能,一般会通过参数 -XX:NewSize 设置新生代初始大小。如果知道新生代初始分配的对象大小(经过监控) ,这样设置会有帮助,可以节省新生代自动扩展的消耗。

-XX:NewRatio
可以设置新生代和老年代的相对大小。这种方式的优点是新生代大小会随着整个堆大小动态扩展。参数 -XX:NewRatio 设置老年代与新生代的比例。例如 -XX:NewRatio=3 指定老年代/新生代为3/1. 老年代占堆大小的 3/4 ,新生代占 1/4 .

如果针对新生代,同时定义绝对值和相对值,绝对值将起作用。下面例子:
$ java -XX:NewSize=32m -XX:MaxNewSize=512m -XX:NewRatio=3 MyApp

以上设置, JVM 会尝试为新生代分配四分之一的堆大小,但不会小于32MB或大于521MB

在设置新生代大小问题上,使用绝对值还是相对值,不存在通用准则 。如果了解应用的内存使用情况,设置固定大小的堆和新生代更有利,当然也可以设置相对值。如果对应用的内存使用一无所知,正确的做法是不要设置任何参数,如果应用运行良好。很好,我们不用做任何额外动作.如果遇到性能或OutOfMemoryErrors, 在调优之前,首先需要进行一系列有目的的监控测试,缩小问题的根源。

-XX:SurvivorRatio
参数 -XX:SurvivorRatio 与 -XX:NewRatio 类似,作用于新生代内部区域。-XX:SurvivorRatio 指定伊甸园区(Eden)与幸存区大小比例. 例如, -XX:SurvivorRatio=10 表示伊甸园区(Eden)是 幸存区To 大小的10倍(也是幸存区From的10倍).所以,伊甸园区(Eden)占新生代大小的10/12, 幸存区From和幸存区To 每个占新生代的1/12 .注意,两个幸存区永远是一样大的..

设定幸存区大小有什么作用? 假设幸存区相对伊甸园区(Eden)太小, 相应新生对象的伊甸园区(Eden)永远很大空间, 我们当然希望,如果这些对象在GC时全部被回收,伊甸园区(Eden)被清空,一切正常.然而,如果有一部分对象在GC中幸存下来, 幸存区只有很少空间容纳这些对象.结果大部分幸存对象在一次GC后,就会被转移到老年代 ,这并不是我们希望的.考虑相反情况, 假设幸存区相对伊甸园区(Eden)太大,当然有足够的空间,容纳GC后的幸存对象. 但是过小的伊甸园区(Eden),意味着空间将越快耗尽,增加新生代GC次数,这是不可接受的。

总之,我们希望最小化短命对象晋升到老年代的数量,同时也希望最小化新生代GC 的次数和持续时间.我们需要找到针对当前应用的折中方案, 寻找适合方案的起点是 了解当前应用中对象的年龄分布情况。

-XX:+PrintTenuringDistribution
参数 -XX:+PrintTenuringDistribution 指定JVM 在每次新生代GC时,输出幸存区中对象的年龄分布。例如:
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大小为 75 MB. 也有关于老年代阀值(tenuring threshold)的信息, 老年代阀值,意思是对象从新生代移动到老年代之前,经过几次GC(即, 对象晋升前的最大年龄). 上例中,老年代阀值为15,最大也是15.

之后行表示,对于小于老年代阀值的每一个对象年龄,本年龄中对象所占字节 (如果当前年龄没有对象,这一行会忽略). 上例中,一次 GC 后幸存对象大约 19 MB, 两次GC 后幸存对象大约79 KB , 三次GC 后幸存对象大约 3 MB .每行结尾,显示直到本年龄全部对象大小.所以,最后一行的 total 表示幸存区To 总共被占用22 MB . 幸存区To 总大小为 75 MB ,当前老年代阀值为15,可以断定在本次GC中,没有对象会移动到老年代。现在假设下一次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

对比前一次老年代分布。明显的,年龄2和年龄3 的对象还保持在幸存区中,因为我们看到年龄3和4的对象大小与前一次年龄2和3的相同。同时发现幸存区中,有一部分对象已经被回收,因为本次年龄2的对象大小为 12MB ,而前一次年龄1的对象大小为 19 MB。最后可以看到最近的GC中,有68 MB 新对象,从伊甸园区移动到幸存区。

注意,本次GC 幸存区占用总大小 84 MB -大于75 MB. 结果,JVM 把老年代阀值从15降低到2,在下次GC时,一部分对象会强制离开幸存区,这些对象可能会被回收(如果他们刚好死亡)或移动到老年代。

-XX:InitialTenuringThreshold, -XX:MaxTenuringThreshold and -XX:TargetSurvivorRatio
参数 -XX:+PrintTenuringDistribution 输出中的部分值可以通过其它参数控制。通过 -XX:InitialTenuringThreshold 和 -XX:MaxTenuringThreshold 可以设定老年代阀值的初始值和最大值。另外,可以通过参数 -XX:TargetSurvivorRatio 设定幸存区的目标使用率.例如 , -XX:MaxTenuringThreshold=10 -XX:TargetSurvivorRatio=90 设定老年代阀值的上限为10,幸存区空间目标使用率为90%。

有多种方式,设置新生代行为,没有通用准则。我们必须清楚以下2中情况:
1 如果从年龄分布中发现,有很多对象的年龄持续增长,在到达老年代阀值之前。这表示 -XX:MaxTenuringThreshold 设置过大
2 如果 -XX:MaxTenuringThreshold 的值大于1,但是很多对象年龄从未大于1.应该看下幸存区的目标使用率。如果幸存区使用率从未到达,这表示对象都被GC回收,这正是我们想要的。 如果幸存区使用率经常达到,有些年龄超过1的对象被移动到老年代中。这种情况,可以尝试调整幸存区大小或目标使用率。

-XX:+NeverTenure and -XX:+AlwaysTenure
最后,我们介绍2个颇为少见的参数,对应2种极端的新生代GC情况.设置参数 -XX:+NeverTenure , 对象永远不会晋升到老年代.当我们确定不需要老年代时,可以这样设置。这样设置风险很大,并且会浪费至少一半的堆内存。相反设置参数 -XX:+AlwaysTenure, 表示没有幸存区,所有对象在第一次GC时,会晋升到老年代。
没有合理的场景使用这个参数。可以在测试环境中,看下这样设置会发生什么有趣的事.但是并不推荐使用这些参数.

结论
适当的配置新生代非常重要,有相当多的参数可以设置新生代。然而,单独调整新生代,而不考虑老年代是不可能优化成功的。当调整堆和GC设置时,我们总是应该同时考虑新生代和老年代。

在本系列的下面2部分,我们将讨论 HotSpot JVM 中老年代 GC 策略,我们会学习“吞吐量GC收集器” 和 “并发低延迟GC收集器”,也会了解收集器的基本准则,算法和调整参数.

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: JVM实用参数(五)新生代垃圾回收

JVM实用参数(五)新生代垃圾回收相关推荐

  1. 深入理解JVM(十五)垃圾回收相关概念

    一.System.gc()的理解 在默认情况下,通过 System.gc () 或者 Runtime.getRuntime().gc() 的调用,会显式触发 Full GC,同时对老年代和新生代进行回 ...

  2. 【JVM】十五、垃圾回收相关算法

    大家好,我是被白菜拱的猪. 一个热爱学习废寝忘食头悬梁锥刺股,痴迷于girl的潇洒从容淡然coding handsome boy. 假如你喜欢我的文字,欢迎关注公众号"放开这颗白菜让我来&q ...

  3. jvm性能调优 - 09白话新生代垃圾回收算法

    文章目录 Pre 复制算法的背景引入 一种不太好的垃圾回收思路 一个合理的垃圾回收思路 复制算法有什么缺点? 复制算法的优化:Eden区和Survivor区 新生代垃圾回收的各种"万一&qu ...

  4. JVM实用参数(四)内存调优

    理想的情况下,一个Java程序使用JVM的默认设置也可以运行得很好,所以一般来说,没有必要设置任何JVM参数.然而,由于一些性能问题(很不幸的是,这些问题经常出现),一些相关的JVM参数知识会是我们工 ...

  5. JVM上篇:内存与垃圾回收篇十四--垃圾回收器

    JVM上篇:内存与垃圾回收篇十四–垃圾回收器 1. GC分类与新能指标 1.1 垃圾回收器概述 垃圾收集器没有在规范中进行过多的规定,可以由不同的厂商.不同版本的JVM来实现. 由于JDK的版本处于高 ...

  6. 第十五章 - 垃圾回收相关算法

    第十五章 - 垃圾回收相关算法 文章目录 第十五章 - 垃圾回收相关算法 1.标记阶段:引用计数算法 1.1 垃圾标记阶段:对象存活判断 1.2 引用计数算法 1.3 小结 2.标记阶段:可达性分析算 ...

  7. JVM实用参数(七)CMS收集器

    原文连接 本文连接  译者: iDestiny  校对:梁海舰 HotSpot JVM的并发标记清理收集器(CMS收集器)的主要目标就是:低应用停顿时间.该目标对于大多数交互式应用很重要,比如web应 ...

  8. JVM内存管理机制和垃圾回收机制

    JVM内存管理机制和垃圾回收机制 JVM结构 图片描述: java源码编译成class文件 class文件通过类加载器加载到内存 其中方法区存放的是运行时的常量.静态变量.类信息等,被所有线程共享 堆 ...

  9. big sur 虚拟机 网络_推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题...

    欢迎关注公众号[Ccww技术博客],原创技术文章第一时间推出 一. JVM内存区域的划分 1.1  java虚拟机运行时数据区 java虚拟机运行时数据区分布图: JVM栈(Java Virtual ...

最新文章

  1. 【C#公共帮助类】10年代码,最全的系统帮助类
  2. 【关于重载OnBackPressed无效的解决方案】
  3. MNN.Tensor exit code -1073740791 (0xC0000409) 解决
  4. 基于界面的银行家算法java实现_java实现银行家算法(Swing界面)
  5. Qt学习笔记之网络和连接
  6. 客户信息管理系统——Java
  7. Angular2学习笔记(六) Angular2 依赖注入
  8. Java虚拟机JVM的内存管理
  9. 阿里云 redis mysql_Redis 和 MySQL数据一致
  10. SurfaceView的经典写法
  11. Java面试必问!Spring事务扩展机制(2)
  12. 2021.12.13(第一周) 实习周记lzhuan
  13. MyBatis下载与简介
  14. 零基础能不能学计算机专业,零基础能学计算机专业吗?
  15. Centos7安装加速下载工具aria2
  16. 算法问题——(树问题集合)
  17. 正则匹配英文括号( 中文括号【 里面的内容 封装工具类
  18. VsCode中运行HTML页面时出现乱码
  19. 360Lib:Lanczos插值
  20. 圆柱模板行业B2B站点打造MIP推送+熊掌号推送+历史普通推送插件

热门文章

  1. Python中的数值类型
  2. OBD技术速成——J1850协议概述
  3. 快速傅里叶变换_计算物理基础:第八章-快速傅里叶变换(FFT)
  4. html5 jquery paint plugin,制作高质量的JQuery Plugin 插件的方法
  5. visual foxpro 程序员指南_如何平衡工作和生活的关系?程序员归来依旧是少年的好方法...
  6. linux查找文件限制时间,Linux查找命令find与文件三种时间
  7. pool python 传参数_Python-爬虫-多线程、线程池模拟(urllib、requests、UserAgent、超时等)...
  8. linux超级密码,找回Linux超级用户root密码
  9. aspose 换行写_aspose.word 换行符 aspose.words换行符
  10. php第一行空白,网页头部多出一行空白问题的解决方法 (PHP文件头BOM问题)