【问题标题】:How do you Force Garbage Collection from the Shell?你如何从 Shell 强制垃圾收集?
【发布时间】:2011-04-01 05:32:57
【问题描述】:

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

我知道您不应该进行强制垃圾回收的做法——您应该弄清楚堆变大/增长的原因。

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

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

【问题讨论】:

标签: java garbage-collection jmx jmap


【解决方案1】:

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

jcmd <pid> GC.run

【讨论】:

【解决方案2】:

如果您运行 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之前的引用。
【解决方案3】:

您可以通过免费的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

【讨论】:

    【解决方案4】:

    除了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
    

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

    【讨论】:

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

    对于 Linux:

    $ jcmd $(pgrep java) GC.run
    

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

    【讨论】:

    • 这似乎只有在有一个 java 进程运行时才有效。否则,它会将第二个 PID 解释为显然无法识别的 jcmd 命令并抛出错误。
    【解决方案6】:

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

    以下示例适用于 cmdline-jmxclient:

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

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

    【讨论】:

      【解决方案7】:

      我认为没有任何命令行选项。

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

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

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

      【讨论】:

        【解决方案8】:

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

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

        【讨论】:

          【解决方案9】:

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

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

          【讨论】:

            【解决方案10】:

            除了user3198490's answer之外,如果你运行jcmd &lt;pid&gt; GC.run后没有任何变化,原因可能是:

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

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

            jcmd &lt;pid&gt; GC.heap_dump filename.hprof

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

            this answer 中提到的 jmap -histo:live &lt;PID&gt; 等其他一些命令也会以同样的方式触发 GC 作为副作用。

            【讨论】:

              【解决方案11】:

              另外:

              • 为具有相同应用程序、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
              

              【讨论】:

                【解决方案12】:

                只是:

                kill -SIGQUIT <PID>
                

                【讨论】:

                • 这将触发堆转储而不是垃圾回收
                • 至少是solaris它做了一个强制GC。
                • 即使在 Solaris 中,SIGQUIT 也不会触发 GC 或堆转储。 SIGQUIT 将仅为 HotSpot 触发线程转储。对于 IBM JVM,它是可配置的。
                • 不会触发GC,只打印堆栈跟踪。
                猜你喜欢
                • 1970-01-01
                • 2015-02-12
                • 2011-05-14
                • 2010-09-16
                • 1970-01-01
                • 2014-06-14
                • 2016-11-11
                • 2011-11-17
                • 1970-01-01
                相关资源
                最近更新 更多