JVM的性能分析

jvm的常用工具

jps

作用:监视java进程状态的工具

命令格式:jps [option][hostid]

参数:
-m:输出启动时传给main函数的方法
-l:输出主类全名如果是jar包,输出路径
-v:输出虚拟机启动时Jvm的参数

jstat

作用:监视java进程各种运行状态的信息

命令格式:jstat[option] vmid [interval][s|ms][count]]

参数:主要分三类、类装在、垃圾收集、运行期编译状况

-class
-gc
-gccapacity
-gcutil
-gccaise
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-complier
-printcompilation

1
2
3
4
5
6
7
8
9
10
11
12
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 6.20 41.42 47.20 16 0.105 3 0.472 0.577

s0、s1:survivor
E:eden区
O:old区
M:metaspace
YGC:minorGc的次数
YGCT:minorGc的时间
FGC:FullGC的次数
FGCT:FullGc的时间
GCT:的时间

jinfo

作用:查看、修改虚拟机的配置。

命令格式:jinfo [option] pid

参数:
-flag <name> to print the value of the named VM flag
-flag [+|-]<name> to enable or disable the named VM flag
-flag <name>=<value> to set the named VM flag to the given value
-flags to print VM flags
-sysprops to print Java system properties

jmap

作用:java内存映射工具,可以查询finalize执行队列、java堆和永久代的详细信息、如空间使用率、当前采用的收集器等

命令格式: jmap [option] <pid>

参数:
-heap 打印java堆详细的信息
-histo[:live] 打印堆中对象统计信息,Live只统计存活的信息
-clstats 打印Classloder的信息
-finalizerinfo 显示F-Queue中等待Finalizer线程执行finalizer方法的对象
-dump:<dump-options> 生成java堆快照:live只打印存活的对象,如果不指定打印所有对象,format=b二进制格式的文件,file=<file>打印到某个<file>中。eg: jmap -dump:live,format=b,file=heap.bin <pid>
-F force. Use with -dump:<dump-options> <pid> or -histo
to force a heap dump or histogram when <pid> does not
respond. The “live” suboption is not supported
in this mode.
-J<flag> to pass <flag> directly to the runtime system

jhat

作用:配合jmap分析dump出来的jmap文件,不建议在应用服务器上使用,因为dump文件很大,并且很耗性能,建议在单独的服务器上执行
命令格式:jhat /dumpfile
使用方法:打开浏览器,访问jhat所在服务器的7000端口。查看内存泄漏用OQL工具和Heap Historygram功能

jstack

作用:java堆栈跟踪工具,定位java每一个线程当前时刻的执行快照,可以定位到线程运行的状况是否死锁等。

命令格式: jmap [option] <pid>

参数:
-F 当正常输出不被响应时候,强制输出程序堆栈
-l 显示关于锁的相关信息
-m 如果调用的是本地方法显示C/C++堆栈

HSDIS

作用:jit生成码反汇编插件,通过jvm设置的参数-XX PrintAssmbly把动态生成的代码还原成汇编代码

命令格式: jmap [option] <pid>

参数:
-F 当正常输出不被响应时候,强制输出程序堆栈
-l 显示关于锁的相关信息
-m 如果调用的是本地方法显示C/C++堆栈

可视化工具

  • JConsole

  • VisualVM

    综上,我们可以用jps jstat jinfo查看jvm的信息。jmap、jhat查看堆信息。jstack查看栈信息。我们可以用可视化工具来方便查看上面的信息推荐VisualVM

    下载地址: http://visualvm.java.net/download.html
    idea可以通过pulgins安装通过简单配置即可实现动态的VisualVM功能

具体案例分析

高性能硬件的场景

如果硬件性能较高,我们一般采用俩种方式

  1. 采用64位虚拟机,设置很大的堆内存
  2. 采用32位虚拟机,虽然堆内存最大设置4(还受限于平台对进程最大使用内存的限制有可能只有2g,windows平台)我们可以给一台服务器设置多个进程+前端反向代理的方法。

    第一种方案我们要注意64位虚拟机往往比32位虚拟机要慢(指针膨胀、内存补齐等需求),另外由于堆内存很大,我们一定要注意大对象导致频繁GC的问题,因为一次fullGC有可能需要停顿10几秒,对于交互多的服务体验会很差

共享缓存导致oom

由于共享缓存频繁的写入导致内存oom。需要检查缓存的使用率。

对外内存导致的oom

有以下几种对外内存

DirectMemory:主要用于nio场景,比如内存环境是2G。我们给堆内存分配了1.6G。那么堆外内存最多只能有0.4G不到,如果这时候大量请求过来会导致oom

线程堆栈:会出现StackOverflowError或者StackOutOfMemoryError

JNI的调用:由于是native方法所以也是堆外内存

Socket的读写Buffer:receive和send都有一个buffer分别是37kb和25kb。如果超出了会出现open many file的错误。

系统线程和gc线程

外部命令导致系统变缓慢

比如调用Runtime.getRuntime.exec()执行shell。java是fork了个进程,这个指令很重如果调用的频繁系统的负载会很重,建议采用api的方式。

外部接口超时导致系统崩溃

调用远程接口响应较慢导致连接大量被占用,同时对连接没做限制导致了虚拟机崩溃。需要设置超时时间,或者采用生产者消费者异步的方式。