jvm 调优实战之 堆内存PSYoungGen 年轻代 大对象,eden ,SurvvorFrom ,SurvvorTo 介绍,minorGC 流程详解以及验证demo和相关jvm配置参数

背景

jvm 是一个老生常谈的话题,可深可浅,我们主要介绍的是jvm调优基础,所以对很深入的原理暂不做介绍
我们本篇主要介绍的是堆内存的PSYoungGen 年轻代先关配置以及用demo触发minorGC

jvm 虚拟机结构

在这里插入图片描述

jvm 数据结构

在这里插入图片描述

jvm 堆内存年轻代,老年代介绍以及相关配置参数

JVM的运行时内存也叫作JVM堆,从GC的角度可以将JVM堆分为新生代、老年代和永久代。其中新生代默认占 1/3堆空间,老年代默认占 2/3堆空间,永久代占非常少的堆空间。新生代又分为Eden区、ServivorFrom区和ServivorTo区,Eden区默认占8/10新生代空间,ServivorFrom区和ServivorTo区默认分别占
1/10新生代空间

在这里插入图片描述

堆内存设置参数

-XmsXXX 初始化大小
-XmxXXX 最大大小
XXX可以是1024M,可以使1G

年轻代大小设置

-XX:NewSize 年轻代大小
-XX:MaxNewSize 年轻代最大大小
比如 -XX:NewSize=512M

年轻代按比例设置大小

-XX:NewRatio=XXX 默认是2,也就是说年轻代和老年代的内存分配值1:2

jvm 年轻代eden ,SurvvorFrom ,SurvvorTo 介绍以及相关配置参数

JVM新创建的对象(除了大对象外)会被存放在新生代,默认占 1/3堆内存空间。由于JVM会频繁创建对象,所以新生代会频繁触发MinorGC进行垃圾回收。新生代又分为Eden区、ServivorTo区和ServivorFrom区,如下所述。
(1)Eden区:Java新创建的对象首先会被存放在Eden区,如果新创建的对象属于大对象,则直接将其分配到老年代。大对象的定义和具体的JVM版本、堆大小和垃圾回收策略有关,一般为
2KB~128KB,可通过XX:PretenureSizeThreshold设置其大小。在Eden区的内
存空间不足时会触发MinorGC,对新生代进行一次垃圾回收。 (2)ServivorTo区:保留上一次MinorGC时的幸存者。
(3)ServivorFrom区:将上一次MinorGC时的幸存者作为这一次MinorGC的被扫描者。

eden,SurvvorFrom ,SurvvorTo 的内存比例参数设置

-XX:SurvivorRatio 配置eden,SurvvorFrom ,SurvvorTo 的内存比例,模式是8
既eden:SurvvorFrom :SurvvorTo = 8:1:1

MinorGC 过程以及大对象大小设置

新生代的GC过程叫作MinorGC,采用复制算法实现,具体过程如下。 (1)把在Eden区和ServivorFrom区中存活的对象复制到ServivorTo区。如果某对象的年龄达到老年代的标准(对象晋升老年代的标准由XX:MaxTenuringThreshold设置,默认为
15),则将其复制到老年代,同时把这些对象的年龄加
1;如果ServivorTo区的内存空间不够,则也直接将其复制到老年代;如果对象属于大对象(大小为
2KB~128KB的对象属于大对象,例如通过XX:PretenureSizeThreshold=2097152设置大对象为
2MB,1024×1024×2Byte=2097152Byte=2MB),则也直接将其复制到老年代。
(2)清空Eden区和ServivorFrom区中的对象。
(3)将ServivorTo区和ServivorFrom区互换,原来的ServivorTo区成为下一次GC时的ServivorFrom区。

年轻代老年代大对象大小设置

Java新创建的对象首先会被存放在Eden区,如果新创建的对象属于大对象,则直接将其分配到老年代
-XX:PretenureSizeThreshold=xxx
xxx 是字节大小


demo代码实现minorGC测试

我们首先配置一个大小为100M的堆内存,年轻代和老年代的比例为1:2,也就是年轻代大小为30M 我们设置大对象的大小为1M,然后程序测试三个情况
情况1:我们创建10个对象为1M的对象,因为没有超过大对象大小,查看是否是放在了年轻代中
情况2:我们创建10个对象为2M的对象,因为没有超过大对象大小,查看是否是放在了老年代中
情况3:我们创建31个1M的对象,因为超过了年轻代大小,查看是否触发了minorGC

***配置如下:
-XX:NewRatio=2
-Xms100M
-Xmx100M
-XX:+PrintGCDetails
-XX:PretenureSizeThreshold=1048576
-XX:SurvivorRatio=8
-XX:+UseSerialGC

首先我们看看空跑main函数年轻代内存使用情况,然后我们计算一下剩余有多大空间够我们创建对象

在这里插入图片描述

我们看到空跑的情况下会有14%的eden内存被虚拟机用来启动,我们剩下的用来测试的内存为86% ,也就是(23+1)M 24个1M对象


情况1测试:我们创建10个对象为1M的对象,因为没有超过大对象大小,查看是否是放在了年轻代中

在这里插入图片描述

我们创建了10M的对象,显示用了eden的51%,去掉空跑的14%,也就是说使用了37%的大小,也就是eden 大小(27M)的37% 也就是9.99M ,符合我们预期


情况2测试:我们创建10个对象为2M的对象,因为没有超过大对象大小,查看是否是放在了老年代中

在这里插入图片描述

我们上图看见,我们创建10个大小为2M的对象,由于我们设置的参数PretenureSizeThreshold=1048576 ,大对象大小为1M,所以会直接将10个2M的 对象直接放入老年代,占用了老年代68288K * 29% 也就刚好是20M,就是刚刚我们
创建的10个2M对象,符合我们预期


情况3测试:由于eden只有23M可以用,我们创建24个1M的对象,因为超过了年轻代大小,查看是否触发了minorGC
在这里插入图片描述
在这里插入图片描述

上面我们说过实际上eden只有23M可用,所以我们分别创建了23个1M对象和24个1M对象, 可以看见前者并没有触发minorGC,符合我们预期


jvm 年轻代大对象调优总结

本节我们主要通过配置年轻代大小以及配置大对象大小来实现了minorGC

如果说我们项目的大对象是相对不变的,比如说商品介绍,活动介绍或者一些相对固定不变的信息
我们完全可以设置大对象的大小上限小于这些对象的最小值,尽量让这些对象直接进入老年代,避免 常驻eden经常引起minorGC
,反之,如果大对象是常变的,那么可以设置大对象大小大于我们的对象 触发minorGC 清除那些常变化的临时大对象

猜你喜欢

转载自blog.csdn.net/madness1010/article/details/129346989
今日推荐