Como você força a coleta de lixo do Shell?

106

Portanto, estou olhando para um heap com jmap em uma caixa remota e quero forçar a coleta de lixo nele. Como você faz isso sem acessar jvisualvm ou jconsole e amigos?

Sei que você não deve forçar a coleta de lixo - você deve apenas descobrir por que a pilha é grande / está crescendo.

Também percebo que System.GC () não força a coleta de lixo - ele apenas informa ao GC que você gostaria que ela ocorresse.

Dito isto, há uma maneira de fazer isso facilmente? Algum aplicativo de linha de comando que estou perdendo?

Eyberg
fonte
Não é o mesmo que stackoverflow.com/questions/1481178/…
Raedwald

Respostas:

25

Você pode fazer isso por meio do programa jmxterm gratuito .

Acenda assim:

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

A partir daí, você pode se conectar a um host e acionar o 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

Consulte os documentos no site jmxterm para obter informações sobre como incorporar isso em scripts bash / perl / ruby ​​/ outros. Eu usei popen2 em Python ou open3 em Perl para fazer isso.

ATUALIZAÇÃO: aqui está um one-liner usando jmxterm:

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

Desde o JDK 7, você pode usar a ferramenta de comando JDK 'jcmd', como:

jcmd <pid> GC.run

user3198490
fonte
22
Por que vocês não me falam sobre essas coisas ?! :)
noahlz
2
se você receber uma "AttachNotSupportedException: Incapaz de abrir o arquivo de soquete", veja meu acréscimo a esta resposta
Thomas Rebele
E se você está entendendo, Explicit GC is disabled, no GC has been performedpode ser devido ao -XX:+DisableExplicitGCargumento VM. Consulte: mail.openjdk.java.net/pipermail/serviceability-dev/2017-August/…
Eyal Roth
Isso funcionará apenas para Oracle JDK, não funcionará para open-jdk.
Ali Saleh
104

Se você executar jmap -histo:live <pid>, isso forçará um GC completo na pilha antes de imprimir qualquer coisa.

Will Hartung
fonte
3
forçar uma coleta de lixo em todos os javas: ps axf | grep java | grep -v grep | awk '{print "jmap -histo: live" $ 1}' | sh
gtrak
1
Onde isso está documentado? E sem: live (por exemplo, quando -F é necessário)?
nafg
7
Olá do misterioso futuro de 2014. jcmdagora é a ferramenta certa para o trabalho.
noahlz
16

Adição à resposta do usuário3198490 . A execução desse comando pode gerar a seguinte mensagem de erro:

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

Isso pode ser resolvido com a ajuda desta resposta stackoverflow

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

onde <process_owner>está o usuário que executa o processo com PID <pid>. Você pode obter tanto de topouhtop

Thomas Rebele
fonte
E quanto ao seguinte? Mesma coisa? java.io.IOException: Operation not permitted
dhockey de
Ainda não encontrei essa mensagem de erro. Talvez funcione com sudo -u <process_owner> jcmd <pid> GC.run, você pode tentar? O comando deve ser seguro
Thomas Rebele de
Eu teria, mas não tenho acesso sudo nessa máquina.
dhockey de
A ferramenta funciona corretamente. Você simplesmente não tem as permissões certas no sistema operacional para executá-lo. O mesmo se aplica a outros aplicativos, mesmo não utilizando Java.
alocado em
6

Existem algumas outras soluções (muitas boas já aqui):

  • Escreva um pequeno código para acessar o MemoryMBean e ligue gc().
  • Usando um cliente JMX de linha de comando (como cmdline-jmxclient , jxmterm ) e execute a gc()operação no MemoryMBean

O exemplo a seguir é para cmdline-jmxclient:

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

Isso é bom porque é apenas uma linha e você pode colocá-la em um script com muita facilidade.

O Alquimista
fonte
5

para linux:

$ jcmd $(pgrep java) GC.run

jcmdé empacotado com o JDK, $(pgrep java)obtém o ID do processo de java

Xuejun Liu
fonte
Isso só funcionará quando houver um processo Java em execução, ao que parece. Caso contrário, ele interpretará o segundo PID como o comando para jcmd que obviamente não é reconhecido e emitirá um erro.
Cas Eliëns
0

Não acho que haja qualquer opção de linha de comando para o mesmo.

Você precisará usar jvisualvm / jconsole para isso.

Eu prefiro sugerir que você use essas ferramentas para identificar por que seu programa está com muita memória.

De qualquer forma, você não deve forçar o GC, pois isso certamente perturbaria o algoritmo do GC e tornaria seu programa lento.

YoK
fonte
0

Se você estiver usando o jolokia com seu aplicativo, poderá acionar uma coleta de lixo com este comando:

curl http://localhost:8558/jolokia/exec/java.lang:type=Memory/gc
máquina de poeira
fonte
-10

somente:

kill -SIGQUIT <PID>
Amin Abbaspour
fonte
4
Isso acionará um despejo de heap, não uma coleta de lixo
Dror Bereznitsky
pelo menos é solaris faz uma força GC.
Amin Abbaspour
2
Nem mesmo no Solaris, o SIGQUIT não acionará um GC ou um despejo de heap. SIGQUIT irá disparar um despejo de thread apenas para HotSpot. Para IBM JVM, é configurável.
Mircea Vutcovici
Não acionará o GC, apenas imprima o rastreamento da pilha.
Elad Tabak