0%

JVM 常用诊断工具小抄

jps

查看 Java 进程及其相关信息。
常用用法:

1
2
jps # 所有 java 进程
jps -mv # 所有 java 进程及启动参数

常用参数:

  • l:输出启动类全类名
  • m:显示 main 方法接收到的参数
  • v:显示 JVM 进程及其接收的参数,通常配合 m 得到进程的启动命令

jinfo

查看或修改 Java 进程其虚拟机的配置项。
常用用法:

1
jinfo -flag <config> <pid> # 查看指定进程的指定配置值

常用参数:

  • flags 主要用来查看对应进程的 非默认 配置项,和 通过命令行 配置的配置项
  • flag [+|-] 针对性查阅指定配置项具体值。在使用 +- 时候可以启用或者禁用对应的布尔配置项
  • sysprops 输出系统变量

jstack

用来导出 Java 程序当前的线程情况。不仅有所有的线程,还有各个线程的优先级、是否守护、线程状态等。通常在服务卡顿时候可能有死循环,通过 jstack 找出在特定方法上大量 RUNABLE 的线程
用法最为简单,只需要:

1
jstack <pid>

jstat

统计 JVM 运行的情况和各项指标,一般在分析问题中十分常用。
基本用法:

1
jstat <-op> [-t] <pid> [interval [count]] # op指定输出类别,t输出JVM启动时间,同时可以指定采样间隔和次数

jstat 常用输出选项

jstat 功能强大几乎面面俱到,这里罗列部分常用的统计信息,详情可以参考 Java11-jstat

  • class 类加载卸载的数量及耗时等
  • compiler JIT 编译器的统计信息
  • gcutil 输出 GC 统计信息以及各区使用量占比
    • S0/S1/E/O/M/CCS: 各区使用量占比(这个可能还是 jmap 更直观)
    • YGC: Young GC 次数
    • YGCT: Young GC 耗时
    • FGC: Full GC 次数
    • FGCT: Full GC 耗时
    • GCT: 全部 GC 累计时间
  • gccausegcutil 基础上增加上一次和当次的 GC 原因

jmap

jmap 用来检查分析 Java 程序的内存状态,比如定位一些内存泄露、内存溢出的情况。
基本用法:

1
jmap <-op> <pid>

jmap 常用输出选项

  • clstats 打印类加载器统计的情况,巨慢,尝试一直未成功…对生产指导意义似乎不大,不太常用
  • heap 输出堆内存的信息,有使用的垃圾回收器、各区大小、当前使用占比以及包括 SurvivorRatio 之类的一些配置信息,十分直观
  • dump 导出内存信息文件,下面会展开。导出文件用来给 MAT 等内存分析工具进行分析,用命令行直接使用 hprof 会稍复杂一些
  • histo:[live] 打印各 Class 的实例数量和占用大小,加上 :live 可以只统计存活对象,可用来确认内存泄露问题,但不如 MAT 强大

内存信息文件

一般生产环境出现内存溢出和泄露都是比较严重的问题。出现了必须即可解决,而如何保留内存溢出时候的案发现场?需要配合两个虚拟机参数了:

  • -XX:+HeapDumpOnOutOfMemoryError 在发生内存溢出时候导入内存镜像
  • -XX:HeapDumpPath=<PATH> 指定导出的内存文件位置

另一个方案就是通过 jmap 来导出了。jmap -dump[:<item>] 有几个子选项(多个间用逗号分开):

  • live 只输出存活对象
  • format=b 保存会 hprof 格式,通常都会指定上
  • file=<fileName> 指定导出的文件名

问题和解决

  1. 关于 jinfo/jmap 出现 Can't attach symbolicator to the process 问题。原因为 Linux 默认不允许使用 ptrace 方位运行的程序内存状态可以:
    1. [建议] 修改 echo 0 > /proc/sys/kernel/yama/ptrace_scope
    2. [永久] 修改 /etc/sysctl.d/10-ptrace.conf 中 kernel.yama.ptrace_scope = 0
谢谢支持!