首页 > 其他分享 >JVM系统优化实践(13):GC动手实践

JVM系统优化实践(13):GC动手实践

时间:2023-04-02 19:32:20浏览次数:34  
标签:1024 13 系统优化 array1 实践 XX GC new byte

您好,我是湘王,这是我的51CTO博客,欢迎您来,欢迎您再来~



上一次留了个小尾巴:怎么以通过代码模拟对象年龄在15岁之后才进入老年代呢?自己试着实现了一下。

首先需要设置好相关的JVM环境:

-XX:InitialHeapSize=104857600 -XX:MaxHeapSize=104857600 -XX:NewSize=20971520 -XX:MaxNewSize=20971520 -XX:MaxTenuringThreshold=15 -XX:SurvivorRatio=6 -XX:PretenureSizeThreshold=10485760 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/work/logs/gc.log

然后准备示例代码:

public static void main(String[] args) {

byte[] array1 = new byte[128 * 1024];

for (int i = 0; i < 20; i++) {

byte[] array2 = new byte[4 * 1024 * 1024];

array2 = new byte[4 * 1024 * 1024];

array2 = new byte[3 * 1024 * 1024];

array2 = null;

}

}

运行后,打印出来的GC日志如下:

JVM系统优化实践(13):GC动手实践_GC实践


可以清除地看到,第15次时,还有存活对象在年轻代。而第16次时,年轻代中已没有任何存活对象。从第16次开始,存活对象始终存在于老年代,大小固定为732K。这就实现了预期的结果。


下面再来动手实现「Survivor空间不足新对象直接进入老年代」的目标。

还是老套路,准备相关JVM设置参数:

-XX:InitialHeapSize=20971520 -XX:MaxHeapSize=20971520 -XX:NewSize=10485760 -XX:MaxNewSize=10485760 -XX:MaxTenuringThreshold=15 -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10485760 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/work/logs/gc.log

然后准备示例代码:

public static void main(String[] args) {

byte[] array1 = new byte[2 * 1024 * 1024];

array1 = new byte[2 * 1024 * 1024];

array1 = new byte[2 * 1024 * 1024];


byte[] array2 = new byte[128 * 1024];

array2 = null;


byte[] array3 = new byte[2 * 1024 * 1024];

}


代码执行前的内存分配是这样的:

JVM系统优化实践(13):GC动手实践_老年代_02


首先执行下面的代码:

byte[] array1 = new byte[2 * 1024 * 1024];

array1 = new byte[2 * 1024 * 1024];

array1 = new byte[2 * 1024 * 1024];


执行过后,创造了3 × 2M的数组,JVM状态为:

JVM系统优化实践(13):GC动手实践_JVM_03


接着执行:

byte[] array2 = new byte[128 * 1024];

array2 = null;

byte[] array3 = new byte[2 * 1024 * 1024];


此时eden空间不足,触发Young GC:

JVM系统优化实践(13):GC动手实践_老年代_04


从打印出来的GC日志可以看到:array3分配到eden区,由于S0和S1都放不下array1,它被直接分配到老年代:

JVM系统优化实践(13):GC动手实践_GC实践_05

JVM系统优化实践(13):GC动手实践_老年代_06


1、Eden区使用了26%,正是array3对象;

2、Survivor From使用了60% = 625K / 1024K,保存存活对象;

3、老年代被使用了2050K,存放的是array1对象。


再来一个实例:通过代码模拟分配一个大对象,让大对象直接进入老年代。

相关JVM参数:

-XX:InitialHeapSize=20971520 -XX:MaxHeapSize=20971520 -XX:NewSize=10485760 -XX:MaxNewSize=10485760 -XX:MaxTenuringThreshold=15 -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=1048576 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/work/logs/gc.log

示例代码:

public static void main(String[] args) {

byte[] array = new byte[2 * 1024 * 1024];

array = null;

}


JVM系统优化实践(13):GC动手实践_老年代_07


通过GC日志可以看到:

1、Eden区有一些未知对象;

2、由于array对象大小超过-XX:PretenureSizeThreshold指定的指,所以没有触发任何GC,array被直接分配到了老年代。


继续实例:老年代空间不足导致触发GC。

相关JVM参数:

-XX:InitialHeapSize=20971520 -XX:MaxHeapSize=20971520 -XX:NewSize=10485760 -XX:MaxNewSize=10485760 -XX:MaxTenuringThreshold=15 -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/work/logs/gc.log

示例代码:

public static void main(String[] args) {

byte[] array1 = new byte[4 * 1024 * 1024];

array1 = null;


byte[] array2 = new byte[2 * 1024 * 1024];

byte[] array3 = new byte[2 * 1024 * 1024];

byte[] array4 = new byte[2 * 1024 * 1024];

byte[] array5 = new byte[128 * 1024];


byte[] array6 = new byte[2 * 1024 * 1024];

}


代码执行前内存分配:

JVM系统优化实践(13):GC动手实践_GC实践_08


执行代码:

byte[] array1 = new byte[4 * 1024 * 1024];

array1 = null;


执行后,创造了1 × 4M的数组,JVM状态为:

JVM系统优化实践(13):GC动手实践_JVM_09


接着继续执行下列代码:

byte[] array2 = new byte[2 * 1024 * 1024];

byte[] array3 = new byte[2 * 1024 * 1024];

byte[] array4 = new byte[2 * 1024 * 1024];

byte[] array5 = new byte[128 * 1024];


此时的JVM内存状态:

JVM系统优化实践(13):GC动手实践_老年代_10


再继续执行:

byte[] array6 = new byte[2 * 1024 * 1024];


此时eden空间不足,触发Young GC,此时的JVM内存状态:

JVM系统优化实践(13):GC动手实践_JVM_11


观察GC日志:

「ParNew (promotion failed): 7419K->8166K(9216K), 0.0023952 secs」

这一行说明回收失败,array2、array3、array4、array5、array6都被引用,一个都回收不掉,空间超过8M。尝试往老年代中存放,此时老年代已有一个4M大小的array1,于是老年代也放不下,触发Full GC。


「CMS: 8194K->6864K(10240K), 0.0026125 secs 11515K->6864K(19456K), [Metaspace: 2755K->2755K(1056768K)], 0.0051233 secs」

这一行说明此时执行了CMS GC,CMS: 8194K->6864K(10240K),表明老年代空间从8M变为6M。同时触发元空间的GC(Metaspace GC)


「CMS: 8194K->6864K(10240K)」

这一行说明:

1、先将array3和array4放入老年代;

2、触发CMS的Full GC,回收掉无用的数组array1;

3、将array2和arrya5再放进去;

4、因此老年代的大小就是array2 + array3 + array4 + array5 = 3 × 2M + 128K;

5、再将array6放到eden区。


Full GC的执行过程是:

JVM系统优化实践(13):GC动手实践_JVM_12


查看Full GC日志:

JVM系统优化实践(13):GC动手实践_老年代_13


可以知道:

1、Eden区使用了26%,正是array6对象;

2、老年代被使用了6864K,存放的是array2~array5对象。


再留几个小尾巴,用代码模拟出另外几种老年代GC场景:

1、触发Young GC前,老年代空间小于历次Young GC后升入老年代的对象的平均大小;

2、老年代被使用率达到92%的阈值。


一些FAQ。

关于reserved、committed、capacity、used和class space的概念澄清:

1、它们并不是纯粹的JVM概念,也和OS紧密相关;

2、reserved是操作系统为JVM进程“保留”的连续的空间,它只是记录JVM需要多少空间,并不会被提交给OS;

3、committed是当JVM进程真正要使用这个连续的空间时,OS真正分配的(也可能会分配失败);

4、capacity和used才属于JVM;

5、capacity反映了容量,used反映了实际使用量;

6、metaspace并不是将全部的空间都用来存放class对象,它还需要放所谓静态变量(比如一个Class Loader被分配了一块内存,这块内存可能并没有被用完,于是就会有产生内存碎片);

7、因此,class space是指实际上被用于放class对象的那块内存的和。



感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

标签:1024,13,系统优化,array1,实践,XX,GC,new,byte
From: https://blog.51cto.com/u_15817148/6164954

相关文章

  • Turtlebot机器人仿真实践
    使用catkin_create_pkg创建一个新的catkin程序包。换到之前创建的catkin工作空间中的src目录下,使用catkin_create_pkg命令来创建一个名为'myPKG'的新程序包,这个程序包依赖于std_msgs和roscpp环境配置在Ubuntu中的操作指令:$source/opt/ros/indigo/setup.bash。    ......
  • 713. 乘积小于 K 的子数组
    力扣题目链接给你一个整数数组 nums 和一个整数 k ,请你返回子数组内所有元素的乘积严格小于 k 的连续子数组的数目。 示例1:输入:nums=[10,5,2,6],k=100输出:8解释:8个乘积小于100的子数组分别为:[10]、[5]、[2],、[6]、[10,5]、[5,2]、[2,6]、[5,2,6]。需要注......
  • AcWing 1013. 机器分配
    总公司拥有 M 台 相同 的高效设备,准备分给下属的 N 个分公司。各分公司若获得这些设备,可以为国家提供一定的盈利。盈利与分配的设备数量有关。问:如何分配这M台设备才能使国家得到的盈利最大?求出最大盈利值。分配原则:每个公司有权获得任意数目的设备,但总台数不超过设备数......
  • RxJava在业务系统中的实践
    在java的世界里由于大多数接口和API都是阻塞式的交互,进而影响到很多童靴的编程思想和编程习惯。因而,有一些专家讲java的编程模型是阻塞式模型(与Node.js区别大),不是没有道理的。从高性能的视角看,任何阻塞点都可能导致性能的退步。而响应式编程其天然就是非阻塞的,当数据准备完成后自动......
  • elasticsearch实践篇:跨表join查询
    随着业务发展跨表join查询需求越来越多,系统的慢查询不断报出,引入ElasticSearch来实现聚合查询势在必行。ES是一个基于Lucene的搜索引擎,通过将业务主表及辅表的索引字段及需要like字段同步到ES里,每张表的索引字段最终汇总成一个联合索引,来实现多个表的跨表搜索。性能要求检索需求......
  • 131A Salas 1
    Version3.0–PitoSalas1COMPUTERSCIENCE131AOPERATINGSYSTEMSPROGRAMMINGASSIGNMENT3CARSANDTUNNELSPRIORITYSCHEDULERIntroductionInthisprogrammingassignmentyouwillimplementapriorityschedulerthatmanagesacollectionofvehiclesattempting......
  • python从入门到实践第16章 下载数据1
    第一步获取csv格式文件需要python爬虫的相关知识 第二步 先打印第一行观察标签importcsvfilename='data/sitka_weather_2014.csv'withopen(filename)asf:reader=csv.reader(f)header_row=next(reader)print(header_row)['AKST','MaxTempe......
  • [LeetCode] 1338. Reduce Array Size to The Half 数组大小减半
    Youaregivenanintegerarray arr.Youcanchooseasetofintegersandremovealltheoccurrencesoftheseintegersinthearray.Return theminimumsizeofthesetsothat atleast halfoftheintegersofthearrayareremoved.Example1:Input:arr=......
  • PostgreSQL 13 pacemaker 高可用集群
    环境介绍 操作系统版本CentOSLinuxrelease7.8.2003(Core)  数据库版本psql(13.10)  PCS集群版本[root@hd-clw-select-proxysql01~]# rpm-qa|greppacemakerpacemaker-libs-1.1.23-1.el7_9.1.x86_64pacemaker-cli-1.1.23-1.el7_9.1.x86_64pacemaker-1.1.2......
  • Ceres 自动求导解析-从原理到实践
    Ceres自动求导解析-从原理到实践目录Ceres自动求导解析-从原理到实践1.0前言2.0Ceres求导简介3.0Ceres自动求导原理3.1官方解释3.2自我理解4.0实践4.1Jet的实现4.2多项式函数自动求导4.3BA问题中的自动求导Reference1.0前言Ceres有一个自动求导功能,只要你按照C......