文章目录

  • 前言
  • 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. 深入支付宝支付扫描支付-跳转支付宝二维码页面支付与自定义生成二维码支付-1参数配置篇

    这里较详细总结一下支付宝扫码支付,从三个方面总结 ①参数配置 ②跳转固定的支付宝页面进行扫码支付 ③自定义二维码扫码支付 参数配置-开放平台相关配置(沙箱环境) 刚开始支付宝的配置参数还是有点让人懵逼 ...

  2. JVM老生代增长过快问题排查

    临近双11期间,大家都忙着发布各种优化版本,程序猿手起键落,满意的敲下最后一个回车键,心里想着这就是双十一最终版了,然而不知道等着他的是下一个双十一最终版-- 版本上线后,观察了几天,程序猿发现一个异 ...

  3. 堆及新生代老生代(学习笔记)

    来自颜群老师的JVM课程 小结 新生代特点 大部分对象都存在新生代 新生代的回收频率高,效率高 老生代特点 空间大,增长速度慢 垃圾回收频率低 划分新老生代的意义 可以根据项目中对象大小的数量,设置新 ...

  4. JVM优化系列-详解JDK1.8 Metaspace 参数配置

    导语   在JVM中除了有堆内存参数配置以外,还有一些其他内存例如方法区.线程栈直接内存等等.他们与堆内存来说是相对比较独立的内存空间.与堆内存相比较这些内存与应用程序本身的关系不大,但是如果将其放到 ...

  5. JVM新生代和老年代的参数——一次ElasticSearch的jvm参数调整

    在测试服务器上发现 ES 进程总是挂掉,于是看 ES 的 gc 情况: 先查到进程的 PID 号,然后使用 jstat 指令: jstat -gc PID 5000 5000 是毫秒,每 5 秒刷新一 ...

  6. java heap最大最小参数_闲谈JVM(一):浅析JVM Heap参数配置

    文章目录 前言 JVM内存模型 堆(Heap)配置 Xms与InitialHeapSize Xmx与MaxHeapSize Heap的缺省配置 Default Heap Size Client JVM ...

  7. JVM 新生代老生代

    堆大小 = 新生代 + 老年代.默认下,新生代 ( Young ) = 1/3 的堆空间大小,老年代 ( Old ) = 2/3 的堆空间大小: 新生代 ( Young ) 被细分为 Eden 和 两 ...

  8. Java架构学习(十二)java内存结构新生代老年代JVM参数调优堆内存参数配置解决堆栈溢出

    JVM参数调优与垃圾回收机制 一.java内存结构 Java内存模型:是多线程里面的,jmm与线程可见性有关 Java内存结构:是JVM虚拟机存储空间. Java内存结构图 Java内存机构分为:方法 ...

  9. Java虚拟机:常见JVM参数配置和GC性能优化

    一.常见的JVM参数配置: 1.垃圾回收统计信息: -XX:+PrintGC     打印GC简要信息 -XX:+PrintGCDetails打印GC的详细信息 -XX:+PrintGCTimeSta ...

最新文章

  1. python中文解释-python是解释型语言么
  2. virtualbox4 剪贴板(共享粘贴板)失效之原因
  3. SQL 性能优化梳理 —— 基本概念、创建时优化、查询时优化
  4. python求素数算法_Python程序最多可计算n个质数(使用不同算法)
  5. 程序员真的是吃青春饭的吗?(献给即将进入职场的程序员们)
  6. Nginx的端口修改问题
  7. 计算机网络要点,计算机网络要点
  8. docker创建镜像之Dockerfile
  9. Access安全性之QA详解
  10. Visual Studio 要求导入 pfx 密钥以及导入后依然要求导入的解决办法
  11. 个人计算机预防勒索病毒,避免电脑中勒索病毒的方法
  12. 使用VST机架效果进行人声处理的顺序及相关插件
  13. nginx reopen
  14. sql范围年龄分组查询人数
  15. 《风之旅人》游戏设计思想二
  16. S3DIS 点云数据集的手动修复问题
  17. echarts 地图 区域合并
  18. 0914WEB漏洞-二次,加解密,DNS等注入
  19. Oracle分析函数七——函数案例
  20. K8S建立ipv6集群

热门文章

  1. 微信小程序入门demo
  2. 推荐一款好用解压RAR、ZIP文件Mac软件,可以输入密码Dr. Unarchiver
  3. 从匿名聊聊被封停,看微信小程序坚持的线下策略
  4. php实现在线抽题,PHP实现类似题库抽题效果
  5. ORA-01438: 值大于为此列指定的允许精度
  6. group by 和where
  7. 宝可梦探险寻宝料理php,宝可梦探险寻宝料理配方 宝可梦探险寻宝食谱一览
  8. 新品周刊 | 可口可乐与时尚包袋品牌Kipling推出联名系列;阿迪达斯推出电竞灵感跑鞋...
  9. 信息泛滥,抽奖集赞:微信如何扼杀了用户的独立和自由
  10. mysql rollback to,MySQL存储过程SAVEPOINT ROLLBACK to