近期公司进行了相关项目的性能测试,经过大半个月的折腾,总算学习了不少相关经验,在此记录分享一番
1.1 jvisualvm
JDK自带的图形化工具,总体来说在性能监控方面要比JConsole好一些,原理都是类似,需要通过JMX等进行JVM分析, 为此如需远端访问,则需要在目标JAVA程序启动时添加如下参数:
-Djava.rmi.server.hostname=[本机IP]
-Dcom.sun.management.jmxremote.port=[监控端口]
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
其它的配置就不在此赘述,相信大家都很容易连上待监测的目标程序,具体界面如下所示:
1.2 jstack
JDK自带工具,用于导出线程信息(也可通过jvisualvm图形化方式导出),具体命令如下:
jstack -l [进程ID]
1.3 jmap
JDK自带工具,用于导出JVM堆内存信息(也可通过jvisualvm图形化方式导出),具体命令如下:
jmap -dump:format=b,file=[文件路径] [进程ID]
1.4 jinfo
JDK自带工具,可动态修改JVM参数,在生产环境下监控问题有时需要,具体命令如下:
jinfo -flag [+|-][name] [进程ID]
jinfo -flat [name]=[value] [进程ID]
1.5 JProfile
大家都说好,单具体还没仔细研究,留待后续补充。。。
2.1 CPU冲高、响应缓慢
这种情况大部分是由于Full GC导致的,具体判断可以通过JVisualVM工具观察内存占用情况,如占用过高,且呈锯齿状,则很可能就是频繁Full GC了。如果JAVA程序启动时加上了如下参数,则可通过观察日志确认是否有Full GC发生(日志会打出[Full GC xxxxx]):
-XX:+PrintGCTimeStamps -XX:+PrintGCDetails
如果启动参数中未加上GC日志,则可通过jinfo动态修改,如下所示:
jinfo -flag +PrintGCDetails [进程ID]
2.2 JAVA堆错误
在生产环境中,很可能由于内存泄漏或高并发导致内存回收后,剩余仍不足2%的情况,此时就会产生如下错误:
java.lang.OutOfMemoryError: Java heap space
所以,为了能够及时分析堆内存,可在Java程序启动参数中添加堆Dump,如下所示:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=%CATALINA_BASE%/logs/dumpfile
2.3 线程分析
在确认Full GC问题之后,先撇开内存泄漏问题,很可能是并发过高导致线程过多,而各线程中的变量占用空间较大从而触发了Full GC。具体确认方法可以通过jstack或者jvisualvm导出线程信息(最好通过top -Hp [进程ID] 打印出所有线程的CPU占用情况),具体要关注两种线程:
如果看上去各个线程均正常,而且线程池未耗尽,然而却触发了Full GC,则可能是由于业务线程中的临时对象过多过大导致的,确认方法也比较简单,使用jmap或者jvisualvm导出业务执行前后的堆Dump信息,比较内存与对象增长情况。此时,具体的优化策略有如下几种:
除了上述状况外,如果仍然业务响应较慢,则需要从单业务流程的角度进行优化,例如使用缓存尽量减少数据库交互等方式。
2.4 内存泄漏分析
如长时间运行出现Java堆溢出、内存随业务增长且回收不掉等情况,很可能是内存泄漏导致,主要策略如下:
上述只是简单介绍,其实定位问题过程还是挺麻烦的,后续要研究JProfile等工具,看是否能高效定位问题。