性能测试之jvm
浅谈一下在性能测试中,遇到java应用出现OOM时(内存泄漏,FGC), 作为非专业java开发的测试人员如何去分析,以及调试jvm参数。
在开始进行测试前,先对jvm内存分配有一个大概的了解.
在jvm内存管理中,新生代与老年代的内存分配比例一般为 新生代:老年代为 1:2。新生代中又分survivor1、survivor2、Eden区,其中这三个分区的比例为 1:1:8,
新生代片区发生的垃圾回收机制称为Minor GC , 老年代片区发生的垃圾回收机制称为Full GC(也有其他的说法)。
触发Minor GC时,回收不掉的对象会短暂存到survivor2中,最后存到Oden区,当老年代内存区不足时触发Full GC,应用程序短暂响应异常,不工作。如果频繁Full GC,此时是不是要骂街了。。。
简单了解jvm的内存管理机制后,作为测试人员,可以从调整内存分配大小方向切入,逐步调整内存参数,观察应用程序运行情况。
先设置的JVM堆参数是:-Xms2048M -Xmx2048M,堆内存分配2G。堆中新生代和老年代默认比例是1:2,那么新生代占600多近700M,新生代又分为Eden和两个survivor区,默认比例8:1:1,按照年新生代700M算,Eden就是560M,survivor区就是70M
假设每秒大概会产生60M的对象。对象一般分配在新生代的Eden区,每秒产生60M的对象,新生代容量是700M,那Eden区大约560M,那么差不多10s不到Eden就满了,JVM就会触发新生代Minor GC,那么,这一秒钟产生的60M堆中就会被放入S区,但是S区只有70M,通过动态年龄判断机制,这60M堆中最终会被移入老年代中。
老年代默认使用比例百分之92会触发Full GC(可以通过-XX:CMSInitiatingOccupancyFraction参数修改这个比例),那么,现在算算多久会触发一次Full GC??老年代大约1300多M,乘以百分之92再除以60,是不是大概20次Minor GC之后就会触发一次Full GC,也就是200s左右
触发Minor GC那一秒的对象是没有进入S区的,由于对象动态年龄判断机制直接进入了老年代,而这种对象一般都是朝生夕死的,Minor GC回收时,会回收Eden和其中一个S区,把存活的对象放入另一个S区;为了避免这种朝生夕死的对象进入老年代,我们可以加大一下年轻代的容量和减少对象进入老年代的年龄阈值。
加大年轻代的容量是为了让S区能放入Minor GC回收Eden区时存活的对象,减少对象进入老年代的年龄阈值是为了让真正老不死的对象提前进入老年代,腾让出S区的空间。
重新设置jvm参数:
Xms3072M -Xmx3072M -Xmn2048M
现在,我们年轻代有2G,那对应的Eden和Survivor区就是1600M、200M和200M,再对应上面的场景,
1600/60,大约27s Eden区才会被放满触发Minor GC,这一秒中产生的60M对象也可以被放入S区,等下一个27s时,Eden和放有垃圾对象的S区会被回收,新的对象放入另一个S区。
这样是不是避免频繁出发Full GC了
同时根据运行情况调整参数 -XX:UseAdaptiveSizePolicy(关闭自动调整survivo大小开关)
一些相关命令:
Jmap -dump 导出dump文件分析堆栈
也可以通过配置JVM,在我们程序OOM时,自动导出dump文件到指定位置
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./ (路径)
jmap -heap pid 查看堆信息
jstat - gc pid 查看gc实时情况
jstack 查看堆栈线程情况
原文链接:https://blog.csdn.net/qq_42809478/article/details/124397680