jvm优化经验总结,jvm调优实战pdf
手动模拟YoungGC的发生。在本文中,我们将通过设置固定堆内存、新一代内存空间等来手动触发年轻GC。然后根据打印出来的GC日志一步步分析整个过程。
让我们首先设置JVM参数。
-XX:NewSize=5242880-XX:MaxNewSize=5242880-XX:initialhaepsize=10485760-XX:MaxHeapSize=10485760-XX:SurvivorRatio=8-XX:PretenureSizeThreshold=1048576 0-XX:useparnewgc-XX:useconcmarksweepgc-XX:printgcdetails-XX:printgcstimestamps-xloggc:GC . log对这些参数进行了解释
XX:NewSize和XX:MaxNewSize:初始新生界和最大新生界的大小分别为5MBXX:InitialHeapSize和XX:MaxHeapSize,分别为10MBXX:SurvivorRatio:新生界伊甸园区和残存区的大小比。8代表伊甸园区,占整个新生代面积的80%。XX:pretenurezethreshold:指定大对象的阈值是10MBUseParNewGC。新一代使用ParNewGC垃圾收集器XX: UseConcMarkSweepGC。老一代用的是CMS垃圾收集器XX:printgdetails:打印详细的GC。XX:printgcstimestamps:打印出每次gc发生的时间Xloggc:gc.log:将GC日志写入gc.log文件相当于分配了10MB的堆内存,新一代的大小为5MB,其中Eden区域占4MB,两个Survivor区域分别占0.5 MB();陈年是5MB,大型对象必须超过10MB才能直接进入陈年。
模拟代码:
公共静态void main(String[] args) {
byte[] array1=新字节[1024 * 1024];//1MB
array1=新字节[1024 * 1024];//1MB
array1=新字节[1024 * 1024];//1MB
array1=null
byte[] array2=新字节[2 * 1024 * 1024];
}代码解析:
第1行:byte [] array1=新字节[1024 * 1024];在new Eden中,分配1MB空间存储array: new byte[1024 * 1024],在main方法栈中,array1指针指向array对象。
\
\
第2行:array 1=new byte[1024 * 1024];在新一代的Eden区,分配1MB空间存储数组:new byte[1024 * 1024],array1指向新数组,于是原数组变成了垃圾对象。
\
第3行:array 1=new byte[1024 * 1024];另一个数组空间被重新分配,array1指向最新的数组对象。这时,在伊甸园区有两个垃圾对象。
\
第4行:Array1=null如果array1没有指向任何对象,那么之前分配的三个数组对象就会变成垃圾对象。代码行5:byte[]array 2=new byte[2 * 1024 * 1024];在伊甸园区域分配2MB的空间。但是由于之前Eden区已经有三个对象,占用了空间的3MB,Eden本身只有4MB,重新分配2MB显然不够,会触发Young GC执行代码,在目录中生成一个gc.log日志文件。我们可以根据这个文件查看GC回收的具体细节,这是我们进行JVM调优的基础。
GC日志分析GC日志如下:
用于bsd-amd64 JRE (1.8.0_321-b07)的Java HotSpot(TM) 64位服务器虚拟机(25.321-b07),由“java_re”于2021年12月15日19:12:29构建,兼容gcc 4.2.1的Apple LLVM 11 . 0 . 0(clang-1100 . 0 . 33 . 17)
内存:4k页面,物理16777216k(45636k空闲)
/proc/meminfo: CommandLine标志:-XX:InitialHeapSize=10485760-XX:MaxHeapSize=10485760-XX:MaxNewSize=5242880-XX:NewSize=5242880-XX:OldPLABSize=16-XX:Pre tenurizethreshold=10485760-XX:PrintGC details-XX:PrintGC timestamps-XX:survivor ratio=8-XX:use
0.125: [GC(分配失败)0.125: [ParNew: 3596K- 420K(4608K),0.0047305秒] 3596K- 1446K(9728K),0.0053325秒] [Times: user=0.01 sys=0.00,real=0.01秒] Heap
par新一代总计4608K,已用3642k[0x 00000007 BF 6000000,0x 000000007 bfb 00000,0x 00000007 bfb 00000]Eden空间4096K,78%已用[0x 000000007 BF 6000000,0x 0000007 BF 925 a40,0x 0000000007 BFA 00000]空间512K,82%已用[82%
这段代码中执行的命令行标志JVM参数包括我们设置的JVM参数和系统默认设置参数。
Gc: 0.125: [GC(分配失败)0.125: [parnew: 3596k-420k (4608k),0.0047305 secs]3596k-1446k(9728k),0.0053325secs] [times:]
0.125:【GC(分配失败)0.125表示系统运行0.125S后,内存分配失败。为什么内存分配会失败?看看我们之前的代码。伊甸园区总空间4MB,之前有过3个垃圾对象。最后,如果需要分配2MB的空间,就会出现内存不足,所以分配失败。这时就会触发一个年轻的GC。
[ParNew: 3596K- 420K(4608K),0.0047305秒]
ParNew是指年轻一代的ParNew垃圾收集器用于垃圾收集,后期的3596K- 420K是指新一代收集前的大小为3.5MB,收集后的420K大小约为0.5MB,相当于此次收集的垃圾对象的3MB左右。0.0047305秒表示此GC恢复需要时间。
新生代区域的总可用大小为4MB 0.5MB=4.5MB,这是伊甸园区域的大小,也是一个幸存者区域的大小。因为两个幸存者区域中的一个需要用来存储幸存对象,而另一个必须保持空闲,所以总的可用大小包括Eden区域的大小和空闲幸存者区域的大小。
396k-1446k (9728K),0.0053325secs]表示整个堆内存空间的使用情况,总大小是9728K,是9.5MB为什么不是10MB?实际上,它移除了一个幸存者区域的存储空间。堆内存空间在GC回收之前是3596K,回收之后是1446K。
堆:堆
par新一代总计4608K,已用3642K [0x00000007bf600000,0x00000007bfb00000,0x 00000007 bfb 00000]
伊甸园空间4096K,78%已用[0x00000007bf600000,0x 0000007 BF 925 a40,0x00000007bfa00000
512K空间中,82%已使用[0x00000007bfa80000、0x00000007bfae9048、0x00000007bfb00000
对于空间512K,使用了0 %[0x00000007bfa00000、0x 00000007 BFA 00000、0x00000007bfa80000
并发标记-扫描生成总计5120K,已用1026k[0x 00000007 bfb 000000、0x00000007c0000000、0x 00000007 c 0000000]
Metaspace使用了3216K,容量4496K,提交了4864K,保留了1056768K
类使用358k,容量388k,提交512k,保留1048576k。这些日志是在JVM退出之前打印出来的,以及当时JVM堆的内存使用情况。
包括新生代使用ParNew GC,Eden,From Survivor area,To Survivor area,老年使用CMS,meta space等的内存使用情况。
版权归作者所有:原创作品来自博主小二上九8,转载请联系作者取得转载授权,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。