JVM那点事-JDK命令行工具+JProfiler的使用(排查线上问题)

1. JDK常用命令

1.1 jps:虚拟机进程状况工具

jps功能:

ps命令类似,可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Classmain()函数所在的类)名称和进程ID。

参数含义:

选项 作用
-q 只输出进程ID,省略主类的名称
-m 输出虚拟机进程启动时传递给主类main()函数的参数
-l 输出主类全名,如果进程执行的是Jar包,输出jar路径
-v 输出虚拟机进程启动时的JVM参数

一般使用JPS直接去获取进程ID。

1.2 jstat:[stæt]虚拟机统计信息监测工具

jstat功能:

监视JVM执行状态信息的命令行工具。显示本地或者远程JVM的类加载、内存、垃圾回收、JIT编译等运行数据,只提供纯文本在控制台的服务器上。是运行期定位JVM性能问题的首选工具。

JVM那点事-JDK命令行工具+JProfiler的使用(排查线上问题)_第1张图片
jstat的用法

我们对jstat -gcutil进行分析:

  • S:两个Survivor区(S0占0%,S1占4.01%空间);
  • E:表示Eden区,使用了72.19%的空间;
  • O:表示Old区,代表老年代;
  • M:代表Permanent,代表永久代;
  • YGC、FGC:代表年轻代,老年代GC次数;
  • YGCT、FGCT、GCT:代表年轻代GC、老年代GC和所有GC的时间。

jstat常用命令

查询单位时间内的GC情况:

jstat -gcutil PID 250 100,250毫秒输出日志,查询100次,查询这段时间内GC情况。看看是不是频繁Full GC导致系统缓慢

1.3 jinfo:Java配置信息工具

jinfo的功能:

实时地查看和调整虚拟机各项参数。

jinfo命令格式:

jinfo [option]
可以使用 jinfo -flag name=value 修改一部分运行期可写的虚拟机参数值。

1.4 jmap:java内存映像工具

jamp的功能:

用于生成堆转储快照(一般称为heapdumpdump文件)如果不使用jmap命令,

  • 可以使用-XX:+HeapDumpOnOutOfMemoryError参数,让虚拟机在OOM异常出现后自动生成dump文件。
  • 或者通过-XX:+HeapDumpOnCtrlBreak参数,则可以使用[Ctrl]+[Break]键让虚拟机生成dump文件。
  • 或者在Linux系统下通过Kill -3命令发送进程退出信号“吓唬”虚拟机,也能拿到dump文件。

jmap的功能:

  1. 获取dump文件;
  2. 查询finalize执行队列;详见JVM那点事-对象的自救计划
  3. Java堆和永久代的详细信息,比如空间使用率,当前用的哪种收集器。

jmap的常用命令:

jmap -histo:live 【pid】> ab.txt 查询内存中对象占比。

jmap -dump:live,format=b,file=tai.dump pid 生成dump文件

1.5 jstack:[stæk]java堆栈跟踪工具

jstack的作用:
命令一般用于生成虚拟机当前时刻的线程快照(一般称为threaddump或者javacore文件)

jstack的目的:
生成线程快照的主要目的就是定位线程出现长时间停顿的原因。

jsatck常用命令:

jstack -l 【线程pid】 查询线程堆栈信息。


2. 使用JProfiler工具分析情况

运行很久的系统突然服务很慢,一般是大量请求进行访问,导致:

  1. 慢查询导致线程阻塞,服务变慢;
  2. 查询大量“大对象”导致频繁GC,服务变慢;

一般生产环境集成skywalking来监控服务的各项指标。

将线上环境dump下的hhh.hprof文件(使用jmap -dump:live,format=b,file=hhh.hprof [pid进程id]得到)使用JProfiler工具打开:

  1. 发现存在大量大对象,这是引起频繁GC的原因
JVM那点事-JDK命令行工具+JProfiler的使用(排查线上问题)_第2张图片
发现存在大量大对象.png
  1. 查看调用栈
JVM那点事-JDK命令行工具+JProfiler的使用(排查线上问题)_第3张图片
查看调用栈.png
JVM那点事-JDK命令行工具+JProfiler的使用(排查线上问题)_第4张图片
image.png
  1. 查看GC Roots
JVM那点事-JDK命令行工具+JProfiler的使用(排查线上问题)_第5张图片
查询GC节点.png
JVM那点事-JDK命令行工具+JProfiler的使用(排查线上问题)_第6张图片
找到问题线程.png
  1. 根据问题线程去定位代码

定位问题代码时,一般情况下是定位com开头的包,并且从下往上去分析线程调用栈。

JVM那点事-JDK命令行工具+JProfiler的使用(排查线上问题)_第7张图片
定位问题代码.png

问题一:线程CPU占用率100%怎么排查?

1. 出现CPU占用率100%原因

  • 业务代码原因,大量线程执行Runnable。
  • GC线程频繁执行,此时一般是发生内存泄漏。

2. 排查CPU占用高的命令:

  1. 定位消耗cpu最高的进程PID;
  2. 根据PID查出消耗cpu最高的线程号;
  3. 根据线程号查出对应的java线程,进行处理;

我们我们进一步思考,需要什么命令?

  • Linux环境中,使用top命令,可以按cpu占用率多少输出PID;
  • 使用top -Hp PID,显示一个进程的线程运行的信息列表。按下[P]可以得到占有率最高线程的PID;
  • 将线程PID转换为十六进制的nid;
  • 使用jstack命令:jstack -l 线程PID> ./文件名打印出来;
  • 使用nid定位到问题所在位置。
  • 若是GC线程频繁执行导致,那么使用JProfiler进行分析。

如何分析jstack输出的threaddump文件?

  1. New:当线程对象创建时存在的状态,此时线程不可被执行;
  2. Runnable:线程处于可运行态,只要得到cpu,就可以执行;
  3. Running:线程正在执行;
  4. Waiting:执行join()或者wait()方法后,表示该线程正处于等待状态,等待某个资源或条件产生唤醒自己;
  5. Timed_Waiting:有时间的等待;
  6. Blocked:阻塞状态,即进入同步方法中,但是没有获得锁;
  7. Dead:线程结束;
  8. Deadlock:表示有死锁;
  9. Waiting on condition:等待某个资源或条件来唤醒自己。比如线程正在sleep或者IO等待;
  10. Waiting on monitor entry:在等待获取锁;
  11. in Object.wait():获取锁之后又执行obj.wait()放弃锁;

小结:
对于jsatck的日志,若是系统运行慢我们要着重关注BlockedWaiting on conditionWaiting on monitor entryDeadlock状态;
若是系统cpu消耗高那么肯定有线程执行死循环,那么需要关注Runnable状态

问题二:如何排查内存泄露和内存溢出

1. 出现内存溢出的原因?

  • 内存中一次性加载的数据量过于庞大,比如一次从数据库获取过多数据。
  • 集合对象中有对象的引用,集合在使用完毕之后未清空。
  • 代码找那个存在死循环或者过多重复的对象实体。
  • JVM启动参数内存值设定过小。
  • 调用ThreadLocal对象但是没有remove()掉。

2. 排查内存溢出的命令
数据在一段时间内一直不正常,十有八九是内存泄露导致的。

  • 使用jps找出正在运行的虚拟机进程ID(PID);
  • 使用jstat分析运行时JVM进程状况,使用jstat -gcutil PID 250 100,250毫秒溢出,查询100次,查询这段时间内GC情况。看看是不是频繁Full GC导致系统缓慢。
  • 使用 jmap命令,内存映像工具。生成heap dump(dump文件)。
  • 使用java heap分析工具——MAT的使用,找出内存占用超出预期的嫌疑对象;
  • 分析MAT中的Histogram柱状图和Dominator Tree支配者树,分析嫌疑对象和其他对象的引用关系(GC Roots路径);
  • 分析程序源码,找出嫌疑对象数量过多的原因。

推荐阅读

Thread Dump 详解

线上linux系统故障排查之一:CPU使用率过高

JProfiler for mac版本下载地址:
链接: https://pan.baidu.com/s/1I4vvdBJRkpKEu7AA_1c1Iw 密码: p2gj
注册码:L-J11-Everyone#speedzodiac-327a9wrs5dxvz#463a59

你可能感兴趣的:(JVM那点事-JDK命令行工具+JProfiler的使用(排查线上问题))