1.2. 背景 系统运行有时会出现一些大大小小的JVM问题,比如cpu load过高、请求延迟、tps降低等,甚至出现内存泄漏(每次垃圾收集使用的时间越来越长,垃圾收集频率越来越高,每次垃圾收集清理掉的垃圾数据越来越少)、内存溢出导致系统崩溃,因此需要对JVM进行调优,使得程序在正常运行的前提下,获得更高的用户体验和运行效率。通过对项目进行jvm信息监控,输出监控数据,通过JVM分析、调优,提升系统性能。吞吐量:程序代码运行时间占总时间的比例(总运行时间 = 程序的运行时间 + 内存回收的时间)暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间(stw 时间)程序的目标不同,调优时所考虑的方向也不同,在调优之前,必须要结合实际场景,有明确的的优化目标,找到性能瓶颈,对瓶颈有针对性的优化,最后进行测试,通过各种监控工具确认调优后的结果是否符合目标。1.3. 目标 1.3.1. JVM调优 2. JVM性能跟踪 2.1. JVM性能跟踪总体方案 通过采集JVM数据,对JVM各项指标进行详细分析,进行JVM性能跟踪,为JVM调优提供依据。2.1.1. 应用运行时间查看
命令:ps -p pid -o etime >> elapsed.log &查看应用具体的堆信息,pid为上一步获取的应用pid1) 系统启动到当前节点运行的时间,用于配合后续GC分析2.1.2. 堆信息查看 命令:jmap -heap pid >> jmapheap.log查看应用具体的堆信息,pid为上一步获取的应用pid2.1.3. 回收信息查看 命令:jstat -gc pid 100 18000 >> jstatgc.log &查看应用具体的回收信息,时间为5个小时,频率为每100毫秒,pid为上一步获取的应用pid1) S0C: 年轻代中第一个survivor(幸存区)的容量(字节)2) S1C: 年轻代中第二个survivor(幸存区)的容量(字节)3) S0U: 年轻代中第一个survivor(幸存区)目前已使用空间(字节)4) S1U: 年轻代中第二个survivor(幸存区)目前已使用空间(字节)5) EC: 年轻代中Eden(伊甸园)的容量(字节)6) EU: 年轻代中Eden(伊甸园)目前已使用空间(字节)13) YGC: 从应用程序启动到采样时年轻代中gc次数14) YGCT: 从应用程序启动到采样时年轻代中gc所用时间(s)15) FGC: 从应用程序启动到采样时old代(全gc)gc次数16) FGCT: 从应用程序启动到采样时old代(全gc)gc所用时间(s)17) GCT: 从应用程序启动到采样时gc用的总时间(s)2.1.4. dump文件收集 获取dump文件,利用分析工具进行分析,MAT,jvisualvm等。需要注意dump会有服务暂停或卡顿,生产环境dump必须进行影响评估。2.1.5. 存活对象分析 2、 获取dump文件,dump会有服务暂停或卡顿,生产环境dump必须进行影响评估。file=/u02/applications/jvm-track/track.dump pid3、 拿到dump文件,可借助分析工具进行分析。以MAT工具为例:查看存活对象主要分布。
2.1.6. Dominator树分析 2、 获取dump文件,dump会有服务暂停或卡顿,生产环境dump必须进行影响评估。file=/u02/applications/jvm-track/track.dump pid3、 拿到dump文件,可借助分析工具进行分析。以MAT工具为例:查看Dominator tree进行对象分析浅堆、深堆。 2.1.7. 内存泄露检测 2、 获取dump文件,dump会有服务暂停或卡顿,生产环境dump必须进行影响评估。file=/u02/applications/jvm-track/track.dump pid3、 拿到dump文件,可借助分析工具进行分析。以MAT工具为例:MAT提供了自动检测内存泄漏,以及统计堆快照内对象分布情况的工具。如图展示了内存泄漏检测工具的使用方法。选择菜单中的LeakSuspects命令,MAT会自动生成一份报告。这份报告罗列了系统内可能存在内存泄漏的问题点。
2.1.8. 大对象查看 2、 获取dump文件,dump会有服务暂停或卡顿,生产环境dump必须进行影响评估。file=/u02/applications/jvm-track/track.dump pid3、 拿到dump文件,可借助分析工具进行分析。以MAT工具为例:查看系统中占用内存最大的几个对象,如果应用程序发生内存泄漏,那么泄漏的对象通常会在堆快照中占据很大的比重。查看和分析堆快照中最大的对象具有较高的价值。
在MAT中,可以自动查找并显示消耗内存最多的几个对象。如上图所示,通过选择TopConsumers命令,可以获取大对象报告。2.1.9. 线程分析 2、 获取dump文件,dump会有服务暂停或卡顿,生产环境dump必须进行影响评估。file=/u02/applications/jvm-track/track.dump pid3、 拿到dump文件,可借助分析工具进行分析。以MAT工具为例:在堆快照中,还包括当前的线程信息,通过MAT可以查看这些信息。如上图通过ThreadDetails、ThreadOverview和ThreadStacks这3个命令,可以根据当前堆快照中的所有线程及线程引用的对象,查看线程详情进行分析。
2.1.10. 集合使用情况分析 2、 获取dump文件,dump会有服务暂停或卡顿,生产环境dump必须进行影响评估。file=/u02/applications/jvm-track/track.dump pid3、 拿到dump文件,可借助分析工具进行分析。以MAT工具为例:可以查看数组、集合的填充率;可以观察集合内的数据;也可以分析哈希表的冲突率。
通过对集合使用情况进行分析,可以更好地了解系统的内存使用情况,查找浪费的内存空间。选择CollectionFillRatio命令,可以展示给定集合的填充率。如图所示为该功能的输出结果,其中显示了填充率为0、20%以下、80%以下和100%以下的集合个数。通过选择HashEntries命令,可以查看Hash表的内容。还可以进一步分析它们的引用情况和其他具体信息。2.1.11. JVM跟踪参考脚本 JVM信息采集脚本,可根据具体需要观察内容,进行脚本调整:3. 优化详细方案
3.1. 优化总体方案 根据性能跟踪、分析,进行JVM调优。优化方案需要根据压测结果对比最终进行调整。3.1.1. 选择合适垃圾收集器 可参考:堆内存4G以下可以用parallel,4-8G可以用ParNew + CMS。3.1.2. 堆内初始值设置 jvm参数的初始值和最大值设置一样,避免扩容时消耗性能。3.1.3. 元空间设置 元空间的大小参数必须要设置,默认是21M,但是它会自动扩容,元空间满了也会触发fullGC,所以一开始就设置好,避免扩容和触发FullGC。-XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M3.1.4. 年轻代、老年代占比 尽可能让对象都在新生代里分配和回收,尽可能别让太多对象频繁进入老年代,避免频繁对老年代进行垃圾回收,同时给系统充足的内存大小,避免新生代频繁进行垃圾回收。扩大年轻代的空间,避免触发对象动态年龄判定机制,尽量避免对象进入老年代,触发FullGC,也可以减少minorGC的频率。如果用parallel,则需要显式的指定比例,parallel默认会动态调整。-XX:-UseAdaptiveSizePolicy -XX:NewRatio=23.1.5. Eden、S0、S1占比 eden区和s0、s1默认是8:1:1,可以调整为6:1:1尽量让每次Young GC后的存活对象小于Survivor区域的50%,都留在年轻代中,避免对象动态年龄判定的触发。尽量别让对象进入老年代,减少FullGC频率,避免频繁fullGC对性能影响。(FullGC时间长,会STW)。如果用parallel,则需要显式的指定比例,parallel默认会动态调整。-XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=63.1.6. 晋升老年代的最大年龄阈 -XX:MaxTenuringThreshold=153.1.7. 开启GC日志 -XX:+PrintTenuringDistribution3.1.8. 调优参数 -XX:-UseAdaptiveSizePolicy -XX:NewRatio=1 -XX:SurvivorRatio=6-XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M-XX:+PrintTenuringDistribution-XX:+PrintTenuringDistribution3.1.9. 参考参数 4核8G,JDK1.8参数参考,具体要以实际项目及调优结果进行设置:-XX:MaxMetaspaceSize=256m-XX:CMSInitiatingOccupancyFraction=92-XX:+UseCMSCompactAtFullCollection-XX:CMSFullGCsBeforeCompaction=0-XX:+CMSParallelInitialMarkEnabled -XX:+CMSScavengeBeforeRemark-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/usr/local/dumdir4. 验证方案 4.1. 优化验证 4.1.1. 调优验证 通过监控堆内存情况,GC详细信息进行验证,验证时间为1个小时。收集堆内存及GC信息。参照2.1JVM性能跟踪总体方案进行验证。
|