So I am looking at a heap with jmap on a remote box and I want to force garbage collection on it. How do you do this without popping into jvisualvm or jconsole and friends?
I know you shouldn't be in the practice of forcing garbage collection -- you should just figure out why the heap is big/growing.
I also realize the System.GC() doesn't actually force garbage collection -- it just tells the GC that you'd like it to occur.
Having said that is there a way to do this easily? Some command line app I'm missing?
Since JDK 7 you can use the JDK command tool 'jcmd' such as:
jcmd <pid> GC.run
If you run jmap -histo:live <pid>
, that will force a full GC on the heap before it prints anything out.
jcmd
is now the right tool for the job.
You can do this via the free jmxterm program.
Fire it up like so:
java -jar jmxterm-1.0-alpha-4-uber.jar
From there, you can connect to a host and trigger 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
Look at the docs on the jmxterm web site for information about embedding this in bash/perl/ruby/other scripts. I've used popen2 in Python or open3 in Perl to do this.
UPDATE: here's a one-liner using jmxterm:
echo run -b java.lang:type=Memory gc | java -jar jmxterm-1.0-alpha-4-uber.jar -n -l host:port
Addition to user3198490's answer. Running this command might give you the following error message:
$ 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 can be solved with help of this stackoverflow answer
sudo -u <process_owner> jcmd <pid> GC.run
where <process_owner>
is the user that runs the process with PID <pid>
. You can get both from top
or htop
java.io.IOException: Operation not permitted
sudo -u <process_owner> jcmd <pid> GC.run
, could you try? The command should be safe
for linux:
$ jcmd $(pgrep java) GC.run
jcmd
is packaged with the JDK, $(pgrep java)
gets the process ID of java
There's a few other solutions (lots of good ones here already):
Write a little code to access the MemoryMBean and call gc().
Using a command-line JMX client (like cmdline-jmxclient, jxmterm) and run the gc() operation on the MemoryMBean
The following example is for the cmdline-jmxclient:
$ java -jar cmdline-jmxclient-0.10.3.jar - localhost:3812 'java.lang:type=Memory' gc
This is nice because it's only one line and you can put it in a script really easily.
I don't think there is any command line option for same.
You will need to use jvisualvm/jconsole for same.
I would rather suggest you to use these tools to identity , why your program is high on memory.
Anyways you shouldn't force GC, as it would certainly disturb GC algorithm and make your program slow.
If you are using jolokia with your application, you can trigger a garbage collection with this command:
curl http://localhost:8558/jolokia/exec/java.lang:type=Memory/gc
Consider using GNU parallel with jcmd as below for multiple processes;
parallel 'jcmd {} GC.run' ::: $(pgrep java)
In addition to user3198490's answer, if nothing really changes after you run jcmd <pid> GC.run
, the reason could be:
GC.run
essentially calls java.lang.System.gc()
, which is just a hint to gc and the JVM is free to ignore it.
If you want to ensure a full GC is FORCED, a choice is to use:
jcmd <pid> GC.heap_dump filename.hprof
The original purpose of this command is to create a heap dump file named filename.hprof
. But as a side effect, in order to reach all the live objects, it "request a full GC unless the -all option is specified".
There are some other commands like jmap -histo:live <PID>
mentioned in this answer triggers GC as a side effect in the same way.
In addition:
To run GC for multi process with the same application, jar file, etc. Use:
jcmd your_application.jar GC.run
To run GC on windows, try:
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
just:
kill -SIGQUIT <PID>
Success story sharing
Explicit GC is disabled, no GC has been performed
that might be due to the-XX:+DisableExplicitGC
VM argument. See: mail.openjdk.java.net/pipermail/serviceability-dev/2017-August/…