6

Java排查JVM问题(进程反应缓慢、僵死、CPU 占用过高、内存等问题)

 2 years ago
source link: https://codeshellme.github.io/2022/03/jvm3/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Java排查JVM问题(进程反应缓慢、僵死、CPU 占用过高、内存等问题)

2022-03-28

1446 字 阅读约需 3 分钟

公号:码农充电站pro

主页:https://codeshellme.github.io

1,ps 找到消耗资源最高的线程 ID

先用 ps 命令找到 Java 进程ID:

ps -aux| grep ...

使用 top 命令查看某进程中的所有线程的资源使用情况:

top -Hp `进程id`

也可以使用如下命令:

ps H -eo pid,tid,%cpu| grep `进程id`

将要分析的线程ID转换成十六进制:

printf "%x\n" `线程ID`

2,jstack 打印线程栈信息

使用 jstack 打印 Java 进程中的线程栈信息

jstack `进程ID`

要特别注意:使用 jstack 命令时的用户一定要与启动 Java 进程的用户一样,否则会出现如下错误

9798: Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding

jstack 输出正常的话,会输出下面一样的信息:

"Thread-34" #613 daemon prio=5 os_prio=0 tid=0x00007fb9b006f800 nid=0x13a9c waiting on condition [0x00007fb90acaa000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000006c10a8828> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

然后,从这些信息中查找某个线程 nid 的状态等信息。

参考资料:

3,JDK 内置命令行工具

命令 含义
jps/jinfo 查看 java 进程
jstat 查看 JVM 内部 gc 相关信息
jmap 查看 heap 或类占用空间统计
jstack 查看线程信息
jcmd 执行 JVM 相关分析命令

4,Java 内存问题排查

一般 Java 内存问题可以通过生成 HeapDump (堆转储)文件来分析,它是一个Java进程在某个时间点上的内存快照。

堆转储文件是诊断内存相关问题的重要信息来源,例如内存泄漏,垃圾收集问题 和 java.lang.OutOfMemoryError,同时它也是优化内存消耗的重要依据。

生成堆转储文件有多种方式:

  • jmap:在服务器上使用该方式比较合适
    • 格式:jmap -dump:format=b,file=<file-path> <pid>
    • 示例:jmap -dump:format=b,file=/opt/tmp/dumpfile.hprof 87960
  • jvisualvm:可视化监控工具

jvisualvm 可以监控 Java 的CPU、堆、类、线程等指标:


要想使用 jvisualvmjconsole 连接,需要先在服务端(Tomcat)开启 jmx 服务,在 Tomcat/bin/setenv.sh 文件中加入:

JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=192.168.0.222" # 服务器IP
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=12345" # 端口

然后需要打开防火墙端口:

firewall-cmd --add-port=12345/tcp --permanent
firewall-cmd --reload

除了打开上面的端口外,还需要打开两个端口,使用 grep 查找:

# 先找到 Tomcat 进程 id
netstat -npl| grep 12345
tcp6 0 0 :::12345 :::* LISTEN 25613/java
# tomcat pid 为 25613
# 再找出其它两个端口
netstat -npl| grep 25613
tcp6 0 0 :::43853 :::* LISTEN 25613/java # 这个
tcp6 0 0 :::12345 :::* LISTEN 25613/java
tcp6 0 0 :::45985 :::* LISTEN 25613/java # 这个
# 将 43853 和 45985 端口也开放
firewall-cmd --add-port=43853/tcp --permanent
firewall-cmd --add-port=45985/tcp --permanent
firewall-cmd --reload
# 查看开放的端口
firewall-cmd --list-ports

生成堆dump 文件后,使用 MemoryAnalyzer 来分析。

MemoryAnalyzer 下载页面:

软件版本解压后目录内有个MemoryAnalyzer.ini文件,该文件里面有个 Xmx 参数,该参数表示最大内存占用量,默认为1024m,根据堆转储文件大小修改该参数即可。

  • MemoryAnalyzer.ini中的参数一般默认为 -vmargs– Xmx1024m,这就够用了。假如你机器的内存不大,改大该参数的值,会导致MemoryAnalyzer启动时,报错:Failed to create the Java Virtual Machine。
  • 当你导出的dump文件的大小大于你配置的1024m(说明1中,提到的配置:-vmargs– Xmx1024m),MAT输出分析报告的时候,会报错:An internal error occurred during: “Parsing heap dump from XXX”。适当调大说明1中的参数即可。

分析示例:

5,Linux 其它监控工具

1,vmstat 命令

vmstat 是一款指定采样周期和次数的功能性监测工具,它不仅可以统计内存的使用情况,还可以观测到 CPU 的使用率、swap 的使用情况。

各项参数的含义:

  • r:等待运行的进程数
  • b:处于非中断睡眠状态的进程数
  • swpd:虚拟内存使用情况
  • free:空闲的内存
  • buff:用来作为缓冲的内存数
  • si:从磁盘交换到内存的交换页数量
  • so:从内存交换到磁盘的交换页数量
  • bi:发送到块设备的块数
  • bo:从块设备接收到的块数
  • in:每秒中断数
  • cs:每秒上下文切换次数
  • us:用户 CPU 使用时间
  • sy:内核 CPU 系统使用时间
  • id:空闲时间
  • wa:等待 I/O 时间
  • st:运行虚拟机窃取的时间

2,阿里 Arthas

文章作者 @码农加油站

上次更改 2022-03-28

JVM性能调优实战笔记2

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK