闲谈JVM(二):浅析新老生代参数配置
文章目录
- 前言
- Heap区新老生代
- 新生代参数配置
- NewSize
- MaxNewSize
- Xmn
- NewRatio
- SurvivorRatio
- 新生代的GC
- 老生代参数配置
- 对象何时进入老生代?
- 老生代GC
- 结语
前言
在上一篇中,我们介绍了JVM中Heap区的基本参数设置,可以参见:闲谈JVM(一):浅析JVM Heap参数配置
在Heap区中,又被划分为几个区域,分别为新生代与老生代,而我们知道,绝大多数的对象都是“朝生夕死”的,在新生代阶段就会被回收掉,由此可以看出,新生代是非常重要的一个区域,而经过多次回收后,仍存活的对象,将进入老生代,本篇,我们就来了解一下新生代与老生代相关的参数配置。
Heap区新老生代
在最开始,我们还是来看一下JVM的内存模型:
从上图中可以看到,Heap区由新生代与老生代组成,而新生代的比重也是比较大的,而进一步细分,新生代中又可以分为三个区域:Eden、Survivor1(From)、Survivor2(To)。
新生代参数配置
新生代的大小配置,主要由几个参数控制:Xmn、NewSize、MaxNewSize、NewRatio、SurvivorRatio。
我们逐个来分说明参数的作用。
NewSize
NewSize是设置新生代有效内存的初始化大小,也可以说是新生代有效内存的最小值,当新生代回收之后有效内存可能会进行缩容,这个参数就指定了能缩小到的最小值。
该参数的使用方式如下:
-XX:NewSize=20m
在Linux环境下,JDK8中该参数的默认大小即为20M。
需要注意的是,该参数仅当Xms与Xmx不一致时,才会在JVM初始化时分配这么大的内存,当Xms与Xmx设置为同一个值时,该参数无效,初始化的新生代大小将会使用MaxNewSize配置的大小。
MaxNewSize
MaxNewSize顾名思义,就是设置新生代有效内存的最大值,当对新生代进行回收之后可能会对新生代的有效内存进行扩容,那到底能扩容到多大,这就是最大值。
NewSize与MaxNewSize是一组参数,分别对应新生代有效内存的最小值与最大值。
该参数的使用方式如下:
-XX:MaxNewSize=100m
在Linux环境下,JDK8中该参数的默认大小为318.5M。
Xmn
Xmn同样是设置新生代的大小,等同于同时设置了NewSize和MaxNewSize,并且值都相等,例如
-Xmn128m
等同于
-XX:NewSize=128m
-XX:MaxNewSize=128m
在绝大多数场景下,对象都是朝生暮死的,在新生代阶段就会被回收掉,在高并发的场景下,会高频创建大量的对象在新生代中,对于这种场景下,可以合理分析堆区内存的情况,适当的调大新生代的大小,避免新生代迅速堆满频繁触发YGC,也可以一定程度的避免对象快速进入老生代。
NewRatio
NewRatio参数表示当前老生代可用内存/当前新生代可用内存的比值,即Old/New,在JDK8中,默认是2,参数使用的方式如下:
-XX:NewRatio=2
我们来验证一下是否是这样的。
写一个简单的Demo:
public class HelloWorld {public static void main(String[] args) {try {Thread.sleep(1000 * 60);} catch(Exception e) {System.out.println("Error");}System.out.println("hello world");}
}
我们设置堆区的大小为30M:
然后来看一下堆区的分配情况:
可以看到,新生代与老生代的比值的确为2,不过这是当JVM初始化时,堆区的一个比例,当运行一段时间,发生GC之后,新生代与老生代的比例不一定遵守这个比例,而是进行动态计算的。
同时需要注意的是,如果设置了Xmn或者NewSize/MaxNewSize,JVM初始化时,那么NewRatio将会被覆盖,即不会生效。
我们来验证一下这个说法是否成立。
启动测试代码,设置堆区大小为30M,新生代大小为20M,然后我们在来看一下内存分布的情况:
可以看到,新生代大小为20M,老生代为10M,也就是说,NewRatio的默认值并未生效。
SurvivorRatio
新生代由Eden和两块Survivor组成,这两块Survivor通常一个叫做From Space,一个叫做To Space,并且两个大小一致,每次GC发生的时候,会将Eden和From Space里的可达对象往To Space里拷贝,或者晋升到Old。
GC完成之后正常情况下是Eden为空的,并且会对换下From Space和To Space的位置,对换完之后的To Space又为空了。
SurvivorRatio表示新生代中三个分代,Eden、Survivor1(From)、Survivor2(To)的比值。
该参数的使用方式如下:
-XX:SurvivorRatio=8
在Linux环境下,JDK8中该参数的默认大小即为8,表示Eden:From:To的比值为8:1:1。
我们来验证一下:
还是启动Demo程序,然后查看:
在看一下真正的内存分布情况:
我们设置JVM参数:
java -Xms30M -Xmx30M -Xmn12M -XX:SurvivorRatio=1 HelloWorld
这里我们将SurvivorRatio设置为1,即Eden:From:To的比值为1:1:1。
使用命令查看内存的实际分布情况:
jstat -gc PID 1000 3
输出结果:
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
4096.0 4096.0 0.0 0.0 4096.0 819.9 18432.0 0.0 2240.0 1.2 0.0 0.0 0 0.000 0 0.000 0.000
4096.0 4096.0 0.0 0.0 4096.0 819.9 18432.0 0.0 2240.0 1.2 0.0 0.0 0 0.000 0 0.000 0.000
4096.0 4096.0 0.0 0.0 4096.0 819.9 18432.0 0.0 2240.0 1.2 0.0 0.0 0 0.000 0 0.000 0.000
其中几个关键的参数:
- S0C survivor0大小
- S1C survivor1大小
- EC Eden区大小
我们可以看到,三个区域的大小均为4096K,即4M,验证了SurvivorRatio参数。
新生代的GC
新生代的GC垃圾回收器,主要有三种,这里简单说明一下:
1、Serial 收集器,它是一个单线程的收集器,但它的单线程的意义并不仅仅说明它只会是使用一个 CPU 或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。
2、ParNew 收集器,ParNew 收集器其实就是 Serial 收集器的多线程版本。ParNew 最重要的一点,是唯一的可以与老生代的CMS 收集器配合使用的新生代收集器,可以通过参数-XX:+UseParNewGC
进行指定。
3、Parallel Scavenge 收集器,它与其他收集器的不同之处在于:它的关注点与其他收集器不同。CMS 等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而 Parallel Scavenge 收集器的目标则是达到一个可控制的吞吐量( Throughput)。
在JDK8中,生产环境中较为常见的组合是新生代的 ParNew GC + 老生代的CMS GC,这套组合也是比较推荐的。
老生代参数配置
上面我们了解完了Heap区中新生代的主要参数配置,那么下面聊一下老生代的配置,关于老生代的参数配置,并不多,老生代的大小 = 堆区大小 - 新生代大小,我们依旧是通过实际情况,验证我们的说法。
启动测试程序,设置堆区大小30M,新生代大小10M,验证老生代大小是否为20M:
java -Xms30M -Xmx30M -Xmn10M HelloWorld
打印内存分布:
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
1024.0 1024.0 0.0 0.0 8192.0 820.1 20480.0 0.0 2240.0 1.2 0.0 0.0 0 0.000 0 0.000 0.000
1024.0 1024.0 0.0 0.0 8192.0 820.1 20480.0 0.0 2240.0 1.2 0.0 0.0 0 0.000 0 0.000 0.000
1024.0 1024.0 0.0 0.0 8192.0 820.1 20480.0 0.0 2240.0 1.2 0.0 0.0 0 0.000 0 0.000 0.000
其中OC一项,为老生代当前大小,为20480K,即20M,验证了我们的说法。
对象何时进入老生代?
我们都知道,对象刚被创建时,一般情况下是会被创建在新生代的,只有超过指定阈值的大对象,才会被直接创建在老生代当中,大多数的对象的生命周期仅存在于新生代,会在新生代阶段就被回收掉了,但是仍有部分对象会进入到老生代中区,那么,新生代的对象何时会进入老生代?
进入到老生代的时机,可以通过参数进行控制:
-XX:MaxTenuringThreshold=15
Each object in Java heap has a header which is used by Garbage Collection (GC) algorithm. The young space collector (which is responsible for object promotion) uses a few bit(s) from this header to track the number of collections object that have survived (32-bit JVM use 4 bits for this, 64-bit probably some more).
对象从新生代晋升到老年代的年龄阈值(每次 Young GC 留下来的对象年龄加一),默认值15,表示对象要经过15次 GC 才能从新生代晋升到老年代。
但是在老生代的CMS GC下,该默认值为6,我们来验证一下,设置GC算法为CMS:
java -Xms30M -Xmx30M -Xmn10M -XX:+UseConcMarkSweepGC HelloWorld
通过jinfo查看:
C:\Users\sheqian.xgy>jinfo -flag MaxTenuringThreshold 12768
-XX:MaxTenuringThreshold=6
可以看到,CMS GC下,晋升的次数默认为6。
不过需要注意的是,当设置了这个值得时候,第一次会以它为准,而在运行阶段,该阈值是动态调整,不过不会超过这个值。
老生代GC
老生代的垃圾收集器,主要分为四种,分别如下:
1、Serial Old 收集器,Serial Old 是 Serial 收集器的老年代版本,它同样是一个单线程收集器,使用 “标记-整理” 算法。一般情况下,不会使用。
2、Parallel old 收集器,Parallel Scavenge 收集器的老年代版本,使用多线程和 “标记-整理” 算法。
3、CMS 收集器,以获取最短回收停顿时间为目标,目前较为推荐的GC 收集器,多数应用于互联网站或者B/S系统的服务器端上。
4、G1 收集器,Java 9以后的默认收集器,当前最炙手可热的GC 收集器,可以说兼顾了性能与时间的GC 收集器。
在Java8中,默认的GC收集器采用了Parallel GC,也可以通过参数-XX:+UseParallelGC
进行指定,来看一下Oracle官方的说法:
The parallel collector (also referred to here as the throughput collector) is a generational collector similar to the serial collector; the primary difference is that multiple threads are used to speed up garbage collection. The parallel collector is enabled with the command-line option
-XX:+UseParallelGC
. By default, with this option, both minor and major collections are executed in parallel to further reduce garbage collection overhead.The parallel collector is selected by default on server-class machines. In addition, the parallel collector uses a method of automatic tuning that allows you to specify specific behaviors instead of generation sizes and other low-level tuning details. You can specify maximum garbage collection pause time, throughput, and footprint (heap size).
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/parallel.html
关于GC 收集器的内容,本篇先不做过多详细的介绍,在后面的篇幅中,会着重对比各个GC 收集器。
结语
本篇,我们介绍了Heap区中新生代与老生代的参数配置,了解了新老生代较为常用的参数配置,其中新生代的参数控制是较为重要的,因为大多数对象在这个阶段就会被回收掉,新生代的大小如果设置过大,会增大YGC的压力,设置过小则会频繁堆满,触发YGC,因此需要根据线上的业务实际情况,酌情调整。
下一篇,我们会对Java8中新增的本地元空间(metaSpace)的参数配置进行介绍,敬请期待。
本篇参考:
JVM 学习——垃圾收集器与内存分配策略:
http://matt33.com/2016/09/18/jvm-basic2/#Parallel-Scavenge-%E6%94%B6%E9%9B%86%E5%99%A8
Oralce官方文档 Parallel Collector:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/parallel.html
JVM监控和调优常用命令工具总结
https://www.cnblogs.com/wxisme/p/9878494.html
闲谈JVM(二):浅析新老生代参数配置相关推荐
- 深入支付宝支付扫描支付-跳转支付宝二维码页面支付与自定义生成二维码支付-1参数配置篇
这里较详细总结一下支付宝扫码支付,从三个方面总结 ①参数配置 ②跳转固定的支付宝页面进行扫码支付 ③自定义二维码扫码支付 参数配置-开放平台相关配置(沙箱环境) 刚开始支付宝的配置参数还是有点让人懵逼 ...
- JVM老生代增长过快问题排查
临近双11期间,大家都忙着发布各种优化版本,程序猿手起键落,满意的敲下最后一个回车键,心里想着这就是双十一最终版了,然而不知道等着他的是下一个双十一最终版-- 版本上线后,观察了几天,程序猿发现一个异 ...
- 堆及新生代老生代(学习笔记)
来自颜群老师的JVM课程 小结 新生代特点 大部分对象都存在新生代 新生代的回收频率高,效率高 老生代特点 空间大,增长速度慢 垃圾回收频率低 划分新老生代的意义 可以根据项目中对象大小的数量,设置新 ...
- JVM优化系列-详解JDK1.8 Metaspace 参数配置
导语 在JVM中除了有堆内存参数配置以外,还有一些其他内存例如方法区.线程栈直接内存等等.他们与堆内存来说是相对比较独立的内存空间.与堆内存相比较这些内存与应用程序本身的关系不大,但是如果将其放到 ...
- JVM新生代和老年代的参数——一次ElasticSearch的jvm参数调整
在测试服务器上发现 ES 进程总是挂掉,于是看 ES 的 gc 情况: 先查到进程的 PID 号,然后使用 jstat 指令: jstat -gc PID 5000 5000 是毫秒,每 5 秒刷新一 ...
- java heap最大最小参数_闲谈JVM(一):浅析JVM Heap参数配置
文章目录 前言 JVM内存模型 堆(Heap)配置 Xms与InitialHeapSize Xmx与MaxHeapSize Heap的缺省配置 Default Heap Size Client JVM ...
- JVM 新生代老生代
堆大小 = 新生代 + 老年代.默认下,新生代 ( Young ) = 1/3 的堆空间大小,老年代 ( Old ) = 2/3 的堆空间大小: 新生代 ( Young ) 被细分为 Eden 和 两 ...
- Java架构学习(十二)java内存结构新生代老年代JVM参数调优堆内存参数配置解决堆栈溢出
JVM参数调优与垃圾回收机制 一.java内存结构 Java内存模型:是多线程里面的,jmm与线程可见性有关 Java内存结构:是JVM虚拟机存储空间. Java内存结构图 Java内存机构分为:方法 ...
- Java虚拟机:常见JVM参数配置和GC性能优化
一.常见的JVM参数配置: 1.垃圾回收统计信息: -XX:+PrintGC 打印GC简要信息 -XX:+PrintGCDetails打印GC的详细信息 -XX:+PrintGCTimeSta ...
最新文章
- python中文解释-python是解释型语言么
- virtualbox4 剪贴板(共享粘贴板)失效之原因
- SQL 性能优化梳理 —— 基本概念、创建时优化、查询时优化
- python求素数算法_Python程序最多可计算n个质数(使用不同算法)
- 程序员真的是吃青春饭的吗?(献给即将进入职场的程序员们)
- Nginx的端口修改问题
- 计算机网络要点,计算机网络要点
- docker创建镜像之Dockerfile
- Access安全性之QA详解
- Visual Studio 要求导入 pfx 密钥以及导入后依然要求导入的解决办法
- 个人计算机预防勒索病毒,避免电脑中勒索病毒的方法
- 使用VST机架效果进行人声处理的顺序及相关插件
- nginx reopen
- sql范围年龄分组查询人数
- 《风之旅人》游戏设计思想二
- S3DIS 点云数据集的手动修复问题
- echarts 地图 区域合并
- 0914WEB漏洞-二次,加解密,DNS等注入
- Oracle分析函数七——函数案例
- K8S建立ipv6集群
热门文章
- 微信小程序入门demo
- 推荐一款好用解压RAR、ZIP文件Mac软件,可以输入密码Dr. Unarchiver
- 从匿名聊聊被封停,看微信小程序坚持的线下策略
- php实现在线抽题,PHP实现类似题库抽题效果
- ORA-01438: 值大于为此列指定的允许精度
- group by 和where
- 宝可梦探险寻宝料理php,宝可梦探险寻宝料理配方 宝可梦探险寻宝食谱一览
- 新品周刊 | 可口可乐与时尚包袋品牌Kipling推出联名系列;阿迪达斯推出电竞灵感跑鞋...
- 信息泛滥,抽奖集赞:微信如何扼杀了用户的独立和自由
- mysql rollback to,MySQL存储过程SAVEPOINT ROLLBACK to