jvm性能排除

查看java进程

1
jps #列出本机所有的jvm实例

部分jps参数

-m:输出主函数传入的参数. 下的 hello 就是在执行程序时从命令行输入的参数 -l: 输出应用程序主类完整 package 名称或 jar 完整名称. -v: 列出 jvm 参数, -Xms20m -Xmx50m 是启动程序指定的 jvm 参数

列出运行中的Java程序的运行环境参数

1
jinfo <pid>

打印每个class的实例数目,内存占用,类全名信息。查看是否有类异常加载

1
jmap -histo <pid>

示例 jvm性能排除_2019-12-19-23-48-31.png

可将上述命令的输出重定向到文件中,然后使用sort -n -k 2命令,根据示例数目进行排序,已确定占用数量较多的实例的类

查看当前内存使用情况

输出Java进程的堆内存信息,包括永久代、年轻代、老年代

1
jmap -heap <pid>

示例 jvm性能排除_2019-12-19-23-58-41.png

实时追踪GC情况

gcutil是按百分比占比输出gc情况的

1
jstat -gcutil <PID> 5000 # 每5秒输出一次gc

S0:  新生代中 Survivor space 0 区已使用空间的百分比 S1: 新生代中 Survivor space 1 区已使用空间的百分比 E: 新生代已使用空间的百分比 O: 老年代已使用空间的百分比 P: 永久带已使用空间的百分比 YGC: 从应用程序启动到当前,发生 Yang GC 的次数 YGCT: 从应用程序启动到当前,Yang GC 所用的时间【单位秒】 FGC: 从应用程序启动到当前,发生 Full GC 的次数 FGCT: 从应用程序启动到当前,Full GC 所用的时间 GCT: 从应用程序启动到当前,用于垃圾回收的总时间【单位秒】

示例 jvm性能排除_2019-12-20-00-04-43.png

jstack

我们已一个简单的代码来示范如何使用

1
2
3
4
5
6
7
8
public class Fooloop {
public static void main(String[] args) {
for (; ; ) {

System.out.println("args = " + args);
}
}
}

启动Fooloop后,使用top命令查看进程使用情况

进程使用,如果信息过多可考虑使用top|grep java,需要清楚哪个是cpu的占用信息,对于下述示例为9 jvm性能排除_2019-12-20-00-39-21.png

我们可以看到pid为 432 的进程cpu占用率很高,我们使用top -Hp <pid>来查看具体是哪个线程cpu占用率高。我们可以看到是433 jvm性能排除_2019-12-20-00-42-52.png

jstack命令生成的日志中,关于nid是使用16进制来表示的,而top不是。我们可以使用printf "%x\n" nid来讲10进制转换为16进制。根据此nidjstack日志中去找到对应的信息。可使用命令jstack <pid> |grep -A 30 <nid>

我们计算出433的十六进制为1b1 jvm性能排除_2019-12-20-00-45-36.png 通过日志,可以看出问题出在Fooloop.main(Fooloop.java:5)

jstack日志中,可以分析是否某个线程持续的输出日志,说明锁的竞争比较激烈,就有可能造成性能问题。我们也可以通过jps -v或者ps -ef|grep java等来查看具体 java 进程的pid