ChatGPT解决这个技术问题 Extra ChatGPT

你如何从 Shell 强制垃圾收集?

所以我在一个远程盒子上查看一个带有 jmap 的堆,我想对其进行强制垃圾收集。你如何在不进入 jvisualvm 或 jconsole 和朋友的情况下做到这一点?

我知道您不应该进行强制垃圾收集的做法——您应该弄清楚为什么堆很大/正在增长。

我也意识到 System.GC() 实际上并没有强制垃圾收集——它只是告诉 GC 你希望它发生。

话虽如此,有没有办法轻松做到这一点?我缺少一些命令行应用程序?


u
user3198490

从 JDK 7 开始,您可以使用 JDK 命令工具“jcmd”,例如:

jcmd <pid> GC.run


为什么你们不告诉我这些事情?! :)
如果您收到“AttachNotSupportedException:无法打开套接字文件”,请参阅 my addition to this answer
如果您得到 Explicit GC is disabled, no GC has been performed,那可能是由于 -XX:+DisableExplicitGC VM 参数。请参阅:mail.openjdk.java.net/pipermail/serviceability-dev/2017-August/…
这仅适用于 Oracle JDK,不适用于 open-jdk。
之前运行 jcmd 以发现所有 java
E
Erica Kane

如果您运行 jmap -histo:live <pid>,这将在打印出任何内容之前强制堆上的完整 GC。


强制对所有 java 进行垃圾回收:ps axf | grep java | grep -v grep | awk '{print "jmap -histo:live " $1}'|sh
这是在哪里记录的?没有 :live 怎么办(例如,当需要 -F 时)?
您好,来自 2014 年的神秘未来。jcmd 现在是完成这项工作的正确工具。
运行“jmap -histo:live ”时,打印结果将包含 gc 之前的引用。
p
pmartin8

您可以通过免费的 jmxterm 程序执行此操作。

像这样启动它:

java -jar jmxterm-1.0-alpha-4-uber.jar

从那里,您可以连接到主机并触发 GC:

$>open host:jmxport
#Connection to host:jmxport is opened
$>bean java.lang:type=Memory
#bean is set to java.lang:type=Memory
$>run gc
#calling operation gc of mbean java.lang:type=Memory
#operation returns: 
null
$>quit
#bye

查看 jmxterm 网站上的文档,了解有关将其嵌入 bash/perl/ruby/其他脚本的信息。我在 Python 中使用 popen2 或在 Perl 中使用 open3 来执行此操作。

更新:这是使用 jmxterm 的单线:

echo run -b java.lang:type=Memory gc | java -jar jmxterm-1.0-alpha-4-uber.jar -n -l host:port

T
Thomas Rebele

除了 user3198490 的答案。运行此命令可能会给您以下错误消息:

$ jcmd 1805 GC.run    
[16:08:01]
1805:
com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded
...

这可以在 this stackoverflow answer 的帮助下解决

sudo -u <process_owner> jcmd <pid> GC.run

其中 <process_owner> 是使用 PID <pid> 运行进程的用户。您可以从 tophtop 获得两者


下面的呢?一样? java.io.IOException: Operation not permitted
我还没有遇到这个错误信息。也许它适用于 sudo -u <process_owner> jcmd <pid> GC.run,你能试试吗?命令应该是安全的
我会有,但我在那台机器上没有 sudo 访问权限。
该工具工作正常。您只是在操作系统中没有正确的权限来执行它。这同样适用于其他应用程序,即使不使用 Java。
A
Andrew Regan

对于 Linux:

$ jcmd $(pgrep java) GC.run

jcmd与JDK打包,$(pgrep java)获取java的进程ID


这仅在似乎有一个 java 进程正在运行时才有效。否则,它会将第二个 PID 解释为 jcmd 的命令,这显然无法识别并引发错误。
T
The Alchemist

还有其他一些解决方案(这里已经有很多好的解决方案了):

编写一些代码来访问 MemoryMBean 并调用 gc()。

使用命令行 JMX 客户端(如 cmdline-jmxclient、jxmterm)并在 MemoryMBean 上运行 gc() 操作

以下示例适用于 cmdline-jmxclient:

$ java -jar cmdline-jmxclient-0.10.3.jar - localhost:3812 'java.lang:type=Memory' gc

这很好,因为它只有一行,您可以很容易地将它放入脚本中。


Y
YoK

我认为没有相同的命令行选项。

您将需要使用 jvisualvm/jconsole 来做同样的事情。

我宁愿建议你使用这些工具来识别,为什么你的程序内存很高。

无论如何,您不应该强制 GC,因为它肯定会干扰 GC 算法并使您的程序变慢。


d
dustmachine

如果您在应用程序中使用 jolokia,则可以使用以下命令触发垃圾回收:

curl http://localhost:8558/jolokia/exec/java.lang:type=Memory/gc

S
San Emmanuel James

考虑将 GNU 与 jcmd 并行用于多个进程,如下所示;

并行'jcmd {} GC.run' ::: $(pgrep java)


x
xdcsy

除了 user3198490's answer,如果在您运行 jcmd <pid> GC.run 后没有真正改变,原因可能是:

GC.run essentially calls java.lang.System.gc(),这只是对 gc 的提示,JVM 可以随意忽略它。

如果要确保强制执行完整的 GC,可以选择使用:

jcmd <pid> GC.heap_dump filename.hprof

此命令的最初目的是创建一个名为 filename.hprof 的堆转储文件。但作为副作用,为了到达所有活动对象,它是“request a full GC unless the -all option is specified”。

this answer 中提到的其他一些命令(如 jmap -histo:live <PID>)以同样的方式触发 GC 作为副作用。


N
Navy Flame

此外:

使用相同的应用程序、jar 文件等为多进程运行 GC。使用:

jcmd your_application.jar GC.run

要在 Windows 上运行 GC,请尝试:

cd C:\"Program Files"\Java\jdk-13.0.2\bin
.\jcmd.exe your_application.jar GC.run

macOS / Linux:

jcmd your_application.jar GC.run
# or
/usr/bin/jcmd your_application.jar GC.run

A
Amin Abbaspour

只是:

kill -SIGQUIT <PID>

这将触发堆转储而不是垃圾收集
至少是solaris它做了一个强制GC。
即使在 Solaris 中,SIGQUIT 也不会触发 GC 或堆转储。 SIGQUIT 将仅为 HotSpot 触发线程转储。对于 IBM JVM,它是可配置的。
不会触发 GC,只是打印堆栈跟踪。