如何从命令行检查正在运行的JVM的堆使用情况?

53

我能否通过命令行检查运行中JVM的堆使用情况,我指的是实际使用情况而不是使用Xmx分配的最大量。

我需要使用命令行,因为我没有访问窗口环境,并且我想要根据此值编写脚本,该应用程序正在Jetty应用服务器上运行。

5个回答

67

谢谢,看起来就是我想要的,不过可能需要一些时间来理解所有的选项,我基本上是在寻找堆使用量。 - Paul Taylor
2
所以我认为OU是关键列,OC显示了分配的最大值。 - Paul Taylor
6
你想要EU和OU列 - 将它们相加可以得到堆中使用的空间量。将EC和OC列加起来可以得到为堆分配的空间量。 - pacoverflow
如果JVM作为一个Linux用户运行,而你以另一个用户登录,你该如何处理? - Kalpesh Soni

21

对于Java 8,您可以使用以下命令行以kB为单位获取堆空间利用率:

jstat -gc <PID> | tail -n 1 | awk '{split($0,a," "); sum=a[3]+a[4]+a[6]+a[8]; print sum}'

这个命令基本上总结了:

  • S0U:生存区0的利用率(kB)。
  • S1U:生存区1的利用率(kB)。
  • EU:伊甸园空间的利用率(kB)。
  • OU:老年代空间的利用率(kB)。

你可能还想包括元空间和压缩类空间的利用情况。在这种情况下,你需要将 a[10] 和 a[12] 添加到 awk 总和中。


13

一次性地完成所有程序。基于@Till Schäfer的回答。

以KB为单位...

jstat -gc $(ps axf | egrep -i "*/bin/java *" | egrep -v grep | awk '{print $1}') | tail -n 1 | awk '{split($0,a," "); sum=(a[3]+a[4]+a[6]+a[8]+a[10]); printf("%.2f KB\n",sum)}'

在 MB 中...

jstat -gc $(ps axf | egrep -i "*/bin/java *" | egrep -v grep | awk '{print $1}') | tail -n 1 | awk '{split($0,a," "); sum=(a[3]+a[4]+a[6]+a[8]+a[10])/1024; printf("%.2f MB\n",sum)}'

"Awk sum"参考:

 a[1] - S0C
 a[2] - S1C
 a[3] - S0U
 a[4] - S1U
 a[5] - EC
 a[6] - EU
 a[7] - OC
 a[8] - OU
 a[9] - PC
a[10] - PU
a[11] - YGC
a[12] - YGCT
a[13] - FGC
a[14] - FGCT
a[15] - GCT

用于“Awk求和”:

a[3] -- (S0U) Survivor space 0 utilization (KB).
a[4] -- (S1U) Survivor space 1 utilization (KB).
a[6] -- (EU) Eden space utilization (KB).
a[8] -- (OU) Old space utilization (KB).
a[10] - (PU) Permanent space utilization (KB).

[参考资料:https://docs.oracle.com/javase/7/docs/technotes/tools/share/jstat.html]

谢谢!

注意:适用于OpenJDK!

进一步问题:信息错误?

如果您使用ps命令检查内存使用情况,您会发现Java 进程消耗了更多的内存...

ps -eo size,pid,user,command --sort -size | egrep -i "*/bin/java *" | egrep -v grep | awk '{ hr=$1/1024 ; printf("%.2f MB ",hr) } { for ( x=4 ; x<=NF ; x++ ) { printf("%s ",$x) } print "" }' | cut -d "" -f2 | cut -d "-" -f1

更新(2021-02-16):

根据以下参考资料(和@Till Schäfer的评论),“ps 可以显示从操作系统保留的内存总量”(经过适应),“jstat 可以显示堆和栈使用空间”(经过适应)。因此,我们看到了 ps 命令和 jstat 命令所指出的差异。

根据我们的理解,最 “真实” 的信息应该是 ps 输出,因为我们将有效地了解系统的内存储备量。而 jstat 命令则用于更详细的分析,关于 Java 在从操作系统中消耗保留内存方面的性能。

[参考资料:http://www.openkb.info/2014/06/how-to-check-java-memory-usage.html]


1
为什么你也在求YGCT的总和?它是一个时间。 - Gamby
2
关于你的问题:ps 显示分配的系统内存而不是堆使用情况。因此,Java 可能会分配未使用的内存。 - Till Schäfer
1
Java进程ID检索无法适用于多个Java进程。最好使用类似于for pid in $(ps -o pid= -C java); do [...] done或者使用jps -m的方法。 - Till Schäfer
@TillSchäfer 我不是很理解你所说的$(ps -o pid= -C java); do [...] done,能否给我们展示一个完整的例子来解释一下呢?这样我就可以进一步丰富我的回答了。谢谢!=D - Eduardo Lucio
@EduardoLucio 您的语句 $(ps axf | egrep -i "*/bin/java *" | egrep -v grep | awk '{print $1}') 在功能上等同于更短的语句 $(ps -o pid= -C java)。第二个语句仅依赖于 ps(而不是 egrep、awk),并且不依赖于 Java 安装的固定路径。此外,jstat 仅接受单个 vm pid。因此,如果有多个 Java 实例,则您的命令将失败。这就是为什么您应该循环遍历所有运行的 vms 的 pid,并为每个 pid 执行 jstat 命令的原因。 - Till Schäfer
显示剩余2条评论

9
如果您在打开gc日志的情况下开始执行,则可以将信息记录到文件中。 否则,“jmap -heap”将提供您所需的内容。 有关更多信息,请参见jmap文档页
请注意,除非绝对必要,否则不应在生产环境中使用“jmap”工具,因为该工具会停止应用程序以确定实际堆使用情况。通常,这在生产环境中是不需要的。

4
如果您使用的是JDK 8及以上版本,请使用jcmd命令:
jcmd GC.heap_info

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接