注意:所有文章除特别说明外,转载请注明出处.
JVM性能调优
[TOC]
系统常用诊断工具
uptime
可以快速查看服务器的负载情况,该命令返回的是系统的平均负载,包括各个分钟之内的任务平均数量,包括正在运行的任务以及可以运行但正在等待某个处理器空闲的任务。
dmesag | tail
该命令输出系统日志的最后10行。
vmstat l
vmstat是实时性能检测工具,可以展现给定时间间隔服务器的状态值,包括服务器的CPU使用率、内存使用、虚拟内存交换情况、IO读写情况等。
mpstat -P ALL l
该命令显示每个cpu的使用情况。
free -m
查看内存的使用情况,-m表示按照兆字节显示
sar -n DEV l
sar命令主要用来查看网络设备的吞吐率。可以以此判断网络设备是否饱和。
top
该命令包含了系统全局的很多指标信息,包括系统负载情况、系统内存使用情况、系统CPU使用情况。
性能分析
CPU分析
在CPU繁忙的时候造成的性能问题主要原因有以下几个。
1. 线程中有无限空循环、无阻塞、正则匹配或者单纯的计算
2. 发生了频繁的GC
3. 多线程的上下文切换
内存分析
1. 堆外内存
2. 堆内内存,通常这部分内存性能相关的有如下几个方面
1. 创建的对象,一般存储在堆中,需要控制好对象的数量和大小,尤其大对象容易进入老年代。
2. 全局集合,通常全局集合的生命周期比较长,因此需要注意。
3. 缓存,缓存选用的数据结构不同会在很大程度上影响内存的大小和GC。
4. ClassLoader,主要动态加载类容易造成永久代内存不足。
5. 多线程,线程分配会占用本地内存,过多线程会造成内存的不足。
上面的各个情况的使用不当会造成:
1. 频繁的GC(stop the world)使得应用响应变慢
2. OOM,直接造成内存溢出错误使得程序退出。OOM的情况分为:
1. heap space:堆内存不足
2. PermGen space:永久代内存不足
3. Native thread:本地线程没有足够内存分配
排查堆内存常见工具是jmap
1. 查看JVM内存使用状况:jmap -heap <pid>
2. 查看JVM内存存活的对象:jmap -histo:live <pid>
3. 将heap里所有对象都dump下来,无论对象是死还是活:jmap -dump:format=b,file=xxx.hprof <pid>
4. 先做一次FULL GC,然后再dump,只包括仍然存活的对象信息:jump -dump:format=b,live,file=xxx.hprof <pid>
IO分析
文件IO
可以使用系统工具pidstat、iostat、vmstat来查看IO状况。
导致IO性能差的原因有如下几个:
1. 大量的随机读写操作
2. 设备慢
3. 文件太大
网络IO
查看网络IO状况一般使用netstat工具。
性能调优
CPU调优
1. 不要存在一直运行的线程,可以使用sleep休眠一段时间
2. 轮询的时候可以使用wait/notify机制
3. 避免循环、正则表达式匹配、计算过多,序列化/反序列化等
4. 避免频繁GC,尤其是FULL GC
在多线程情况下:
1. 多线程使用的时候,减少线程数量和线程的切换,使用线程池
2. 多线程对于锁的竞争可以考虑减少锁的粒度(ReentrantLock)等。
内存调优
内存调优主要是对JVM调优的调优。
1. 合理设置各个代的大小,避免新生代设置过小(不够用,经常Minor GC并进入老年代)以及过大(会产生碎片),同样避免Survivor设置过大和过小。
1. 新生代大小选择,响应时间优先的应用,尽可能设大,直到接近系统的最低响应时间限制。在这种情况下,新生代回收发生GC的频率是最低的。同时,也能够减少到达老年代的对象。吞吐量优先的应用,也应尽可能的设置大些,因为对响应时间没有要求,垃圾回收可以并行进行。
2. 老年代大小选择,响应时间优先的应用,老年代一般都是使用并发回收器。所以大小设置需要小心。
2. 选择合适的GC策略
3. 老年代优先使用Parallel GC(-XX:+UseParallel[Old]GC),可以保证最大的吞吐量。由于CMS会产生碎片,确实有必要才改成CMS或G1。
4.
JVM参数设置
JVM的参数配置在很大程度上影响Java应用的性能。
启动参数配置
1. java -XX:+PrintCommandLineFlags 通过该参数来查看所有可以设置的参数及其默认值,或者在程序启动的时候加:-XX:+PrintCommandLineFlags 查看与默认值不同的启动参数。或查看所有启动参数:-XX:PrintFlagsFinal。
提示:jinfo -flags [pid] 查看目前启动使用的有效参数。 jinfo -flag [fileName] [pid] 查看对应参数的值
动态设置参数
在Java应用启动之后发现是GC造成的性能问题,但启动的时候没有加入打印GC的参数,动态参数可以解决这个问题。
jinfo -flag [-/+][flagName] [pid] 启动或禁用某个参数
jinfo -flag [flagName=value] [pid] 设置某个参数的值
对于上面的GC问题,可以使用命令打开HeapDump并设置dump路径。
jinfo -flag +HeapDumpBeforeFullGC [pid]
jinfo -flag +HeapDumpAfterFullGC [pid]
jinfo -flag +HeapDumpPath=/... [pid]
同样地,可以动态关闭
jinfo -flag -HeapDumpBeforeFullGC [pid]
jinfo -flag -HeapDumpAfterFullGC [pid]
-verbose:gc | -XX:+PrintGCDetails
很多GC推荐设置都同时设置这两个参数,其实只要打开了 -XX:+PrintGCDetails,前面选项也会被同时打开,无需重复设置。
-XX:+DisableExplicitGC
该参数的作用使得 system.gc变为空调用,很多推荐设置里面都建议开启该参数。
….