Как заставить сборку мусора из оболочки?

107

Итак, я смотрю на кучу с jmap на удаленном компьютере и хочу принудительно запустить сборку мусора. Как это сделать, не заходя в jvisualvm или jconsole и друзей?

Я знаю, что вы не должны практиковать принудительную сборку мусора - вам просто нужно выяснить, почему куча большая / растет.

Я также понимаю, что System.GC () на самом деле не вызывает сборку мусора - он просто сообщает GC, что вы хотите, чтобы это произошло.

Сказав, что есть способ сделать это легко? Мне не хватает какого-то приложения командной строки?

Эйберг
источник
Не то же самое, что stackoverflow.com/questions/1481178/…
Raedwald

Ответы:

25

Вы можете сделать это с помощью бесплатной программы jmxterm .

Запустите его так:

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

Оттуда вы можете подключиться к хосту и запустить сборщик мусора:

$>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 ​​/ other. Для этого я использовал popen2 в Python или open3 в Perl.

ОБНОВЛЕНИЕ: здесь однострочник с использованием jmxterm:

echo run -b java.lang:type=Memory gc | java -jar jmxterm-1.0-alpha-4-uber.jar -n -l host:port
Гарольд Л
источник
347

Начиная с JDK 7 вы можете использовать командный инструмент JDK 'jcmd', например:

jcmd <pid> GC.run

user3198490
источник
22
Почему вы не рассказываете мне об этих вещах ?! :)
noahlz
2
если вы получите «AttachNotSupportedException: Невозможно открыть файл сокета», см. мое добавление к этому ответу
Thomas Rebele
И если вы получаете Explicit GC is disabled, no GC has been performedэто, возможно, из-за -XX:+DisableExplicitGCаргумента VM. См .: mail.openjdk.java.net/pipermail/serviceability-dev/2017-August/…
Eyal Roth
Это будет работать только для Oracle JDK, это не будет работать для open-jdk.
Али Салех
104

Если вы запустите jmap -histo:live <pid>, это вызовет полный сбор мусора в куче, прежде чем он что-либо распечатает.

Уилл Хартунг
источник
3
принудительно выполнить сборку мусора на всех javas: ps axf | grep java | grep -v grep | awk '{print "jmap -histo: live" $ 1}' | sh
gtrak
1
Где это задокументировано? А как насчет без: live (например, когда нужен -F)?
nafg
7
Привет из загадочного будущего 2014 года. jcmdТеперь правильный инструмент для работы.
noahlz
16

Дополнение к user3198490 ответу «s. При выполнении этой команды может появиться следующее сообщение об ошибке:

$ 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
...

Это можно решить с помощью этого ответа stackoverflow

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

где <process_owner>пользователь, запускающий процесс с PID <pid>. Вы можете получить как от, так topиhtop

Томас Ребеле
источник
А как насчет следующего? То же самое? java.io.IOException: Operation not permitted
dhockey 09
Я еще не сталкивался с этим сообщением об ошибке. Может сработает sudo -u <process_owner> jcmd <pid> GC.run, не могли бы вы попробовать? Командование должно быть безопасным
Томас Ребеле
Я хотел бы, но у меня нет доступа к sudo на этой машине.
dhockey
Инструмент работает правильно. У вас просто нет необходимых разрешений в операционной системе для его выполнения. То же самое и с другими приложениями, даже не использующими Java.
Aled 03
6

Есть еще несколько решений (здесь уже много хороших):

  • Напишите небольшой код для доступа к MemoryMBean и позвоните gc().
  • Используя JMX-клиент командной строки (например, cmdline-jmxclient , jxmterm ) и запустите gc()операцию на MemoryMBean

Следующий пример предназначен для cmdline-jmxclient:

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

Это хорошо, потому что это всего одна строка, и вы можете очень легко вставить ее в сценарий.

Алхимик
источник
5

для Linux:

$ jcmd $(pgrep java) GC.run

jcmdупакован с JDK, $(pgrep java)получает идентификатор процесса java

Сюэцзюнь Лю
источник
Это будет работать только тогда, когда кажется, что запущен один java-процесс. В противном случае он будет интерпретировать второй PID как команду для jcmd, которая явно не распознается, и выдаст ошибку.
Cas Eliëns,
0

Я не думаю, что для этого есть какой-либо параметр командной строки.

Для этого вам нужно будет использовать jvisualvm / jconsole.

Я бы посоветовал вам использовать эти инструменты, чтобы определить, почему ваша программа занимает много памяти.

В любом случае вы не должны форсировать сборщик мусора, так как это наверняка нарушит алгоритм сборщика мусора и замедлит вашу программу.

ЙоК
источник
0

Если вы используете jolokia в своем приложении, вы можете запустить сборку мусора с помощью этой команды:

curl http://localhost:8558/jolokia/exec/java.lang:type=Memory/gc
пылесос
источник
-10

просто:

kill -SIGQUIT <PID>
Амин Аббаспур
источник
4
Это вызовет дамп кучи, а не сборку мусора
Дрор Березницкий
по крайней мере, Solaris делает GC Force.
Амин Аббаспур,
2
Даже в Solaris SIGQUIT не запускает ни сборщик мусора, ни дамп кучи. SIGQUIT вызовет дамп потока только для HotSpot. Для IBM JVM это настраивается.
Мирча Вутцовичи
Не запускает GC, просто распечатайте трассировку стека.
Элад Табак