JVM工具

首先,JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。

一、jps(Java Process Status)

用于查看有权访问的虚拟机的进程,并显示他们的进程号

-v:列出虚拟机进程启动时的 JVM 参数。比如:-Xms20m -Xmx50m 是启动程序指定的 jvm 参数

二、jstat(JVM Statistics Monitoring Tool)

可以用来监视 JVM 内存内的各种堆和非堆的大小及其内存使用量、类装载、垃圾收集、JIT 编译等运行数据

jstat - [-t] [-h] [ []]

-gc:显示堆各分区大小、YGC,FGC次数和时长。包括 Eden 区、两个 Survivor 区、老年代、永久代等的容量、已用空间、GC 时间合计等信息

-gccapacity:显示内容与 -gc 基本相同,但输出主要关注 Java 堆各个区域使用到的最大、最小空间

-gcutil:显示内容与 -gc 基本相同,但输出主要关注已使用空间占总空间的百分比

-gccause:与 -gcutil 功能一样,但是会额外输出导致最后一次或当前正在发生的 GC 产生的原因

-gcnew:显示新生代 GC 状况

-gcnewcapacity:显示内容与 -gcnew 基本相同,输出主要关注使用到的最大、最小空间

-geold:显示老年代 GC 状况

-gcoldcapacity:显示内容与 -gcold 基本相同,输出主要关注使用到的最大、最小空间

-gcpermcapacity:显示永久代使用到的最大、最小空间

interval 参数:用于指定输出统计数据的周期,单位为毫秒。即:查询间隔

count 参数:用于指定查询的总次数

OOM案例:比较GC时长(GCT列)占运行市场的比例:

如果该比例超过 20%,则说明目前堆的压力较大;

如果该比例超过 98%,则说明这段时期内几乎一直在GC,堆里几乎没有可用空间,随时都可能抛出 OOM 异常

内存泄露案例

每隔一段较长的时间采样多组 OU(老年代内存量) 的最小值,如果这些最小值在上涨,说明无法回收对象在不断增加,可能是内存泄漏导致的。

在长时间运行的 Java 程序中,我们可以运行 jstat 命令连续获取多行性能数据,并取这几行数据中 OU 列(Old Used,已占用的老年代内存)的最小值

然后,我们每隔一段较长的时间重复一次上述操作,来获得多组 OU 最小值。

如果这些值呈上涨趋势,则说明该 Java 程序的老年代内存已使用量在不断上涨,这意味着无法回收的对象在不断增加,因此很有可能存在内存泄漏(不再使用的对象仍然被引用,导致GC无法回收)

三、jstack(JVM Stack Trace)

用于生成虚拟机指定进程当前时刻的线程快照(虚拟机堆栈跟踪)

参数:

-F 当正常输出的请求不被响应时,强制输出线程堆栈

-l 除堆栈外,显示关于锁的附加信息

线程快照:该进程内每条线程正在执行的方法堆栈的集合。

生成线程快照的作用:可用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。

这些都是导致线程长时间停顿的常见原因。当线程出现停顿时,就可以用 jstack 显示各个线程调用的堆栈情况。

在 thread dump 中,要留意下面几种状态

  • 死锁,Deadlock(重点关注)
  • 等待资源,Waiting on condition(重点关注)
  • 等待获取监视器,Waiting on monitor entry(重点关注)
  • 阻塞,Blocked(重点关注)
  • 执行中,Runnable
  • 暂停,Suspended
  • 对象等待中,Object.wait() 或 TIMED_WAITING
  • 停止,Parked

四、jmap(Memory Map)和jhat(Java Heap Analysis Tool)

jmap:打印出某个 JVM 进程内存内的所有对象的情况,一般用于查看内存占用情况。一般结合jhat使用

使用jmap -histo[:live] pid查看堆内存中的对象数目、大小统计直方图,如果带上live则只统计活对象,

jmap进行dump命令格式 jmap -dump:format=b,file=dumpFileName pid

五、Visual VM

六、jconsole:

一个 GUI 监视工具,可以以图表化的形式显示各种数据,并支持远程连接