今天我们运用jvm的命令,来观察一个模拟程序的GC情况,以及GC频繁的情况下,如何进行参数调整。
模拟程序
此程序起个5个线程任务,每个任务在不停的在创建对象。每个任务新建了1M的字节数组。我们设置java运行参数为 xms60M,xms60M,后续观察下程序GC情况
运行java程序后,观察一下jvm的运行情况。
1.运行 jps获取进程号
2.首先我们运用 jmap -heap 17528查看下jvm内存的分配情况
jmap -heap 输出内容解析
MinHeapFreeRatio:最小堆空闲比率。
MaxHeapFreeRatio:最大堆空闲比率。
MaxHeapSize:最大堆大小,我们配置了60M
NewSize:新生代大小,分配了20M,因为NewRatio默认是2,60*1/3 = 20M
MaxNewSize:新生代最大大小,也是20M。
OldSize:老年代大小,分配了40M,因为NewRatio默认是2
NewRatio:新生代和老年代的比率。由图可知,新生代为20M,老年代为40M,比例为2。
SurvivorRatio:eden和from,to其中一个的比例占新生代的比例,可见from,to=20/8=2.5M
Eden Space:SurvivorRatio=8可得出,20*(1-1/8-1/8)=15M
MetaspaceSize:元空间大小(Java 8 及之后版本)。
CompressedClassSpaceSize:压缩类空间大小(Java 8 及之后版本)。
重点配置解析
NewSize 因为NewRatio默认是2,所以可得出 NewSize 占用内存为 60*1/3,
eden分配了15M,由默认参数SurvivorRatio=8可得出,20*(1-1/8-1/8)=15
survivorFrom和survivorTo都分配了2.5M(20*1/8)。猜想一下当年轻代配置内存很小的情况下,GC是会比较频繁的,那么我们用jstat命令观察下真实的GC情况
观察GC情况
jstat -gcutil pid 1000 ,每秒打印一下GC情况
由图观察,基本没1秒就会进行一次YGC ,原因显而易见,注意,这里的指标代表利用率,而不是用了多少M。那么问题来了,在服务器内存不变的情况下,如何才能降低YGC的频率。分析本实例代码可知,线程的生命周期大概在一秒运行完成,数组对象largeArray即可进行回收,不会晋级到老年代,那么,是否老年代可以腾出一部分空间来给新生代。那么是否可以调整下新生代和老年代的比例,让新生代占用更多的内存,老年代占用更少的内存,来缓解YGC的情况。注意,本优化只针对此代码,不同的场景,所占用的内存情况不一样,需要具体场景具体分析。
我们将 NewRatio参数调整为1,-XX:NewRatio=1
打印下内存配置
此时,NewSize = 30M,OldSize =30 各占一半的内存
再次运行程序后,每秒打印一下GC情况
观察YGC指标可知,原先1秒一次的YGC,经过调整-XX:NewRatio=1参数,缩减为了3秒一次YGC
终结
本次优化,每个任务线程每秒钟产生一个1M的数组,以为没有什么实例变量占用内存,方法堆栈运行完后,没有任何对象需要存活,即可被垃圾回收,那么可以推断,老年代并不需要占用很多的内存。根据这一特性,我们调整一下-XX:NewRatio=1参数,加大了NewSize内存的占比,因此降低了GC的频率。
命令行的方式,很多指标的观察不是很方便,后续小编计划写一篇图形化工具的监控工具Jvisualvm的使用教程,创作不易,欢迎点赞收藏。
标签:实战,NewSize,YGC,新生代,调优,GC,内存,JVM,NewRatio From: https://blog.csdn.net/da120213828/article/details/136754029