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?


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

346

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

jcmd <pid> GC.run


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.


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


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.


5

para linux:

$ jcmd $(pgrep java) GC.run

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


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.


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

-10

somente:

kill -SIGQUIT <PID>

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.