É possível forçar a coleta de lixo em Java, mesmo que seja complicado? Eu sei sobre System.gc();
e Runtime.gc();
mas eles apenas sugerem fazer GC. Como posso forçar o GC?
java
garbage-collection
Robert Columbia
fonte
fonte
Respostas:
Sua melhor opção é chamar o
System.gc()
que simplesmente é uma dica para o coletor de lixo que você deseja que ele faça uma coleção. Não há como forçar e coletar imediatamente, pois o coletor de lixo não é determinístico.fonte
non-deterministic == trouble
GC.Collect()
não coleta. Em Javagc()
faz.A biblioteca jlibs possui uma boa classe de utilitário para coleta de lixo . Você pode forçar a coleta de lixo usando um truque bacana com objetos WeakReference .
RuntimeUtil.gc () dos jlibs:
fonte
PhantomReference
com aReferenceQueue
e você seria notificado após a finalização, mas ainda antes da limpeza. Por fim, mesmo que você tenha detectado com êxito que a memória desse objeto foi recuperada, isso ainda significaria muito pouco em um GC geracional como o HotSpot. Geralmente coincidiria com a limpeza da geração jovem.System.gc(); System.gc();
, mas com certeza seria interessante saber se funcionou melhor do que isso. De fato, apenas imprimir quantas vezes ele chamouSystem.gc()
seria suficiente. A chance de chegar a 2 é bastante pequena.A melhor maneira (se não apenas) de forçar um GC seria escrever uma JVM customizada. Eu acredito que os coletores de lixo são conectáveis, então você provavelmente pode escolher uma das implementações disponíveis e ajustá-la.
Nota: Esta NÃO é uma resposta fácil.
fonte
Usando a interface da Java Virtual Machine Tool (JVM TI) , a função
"Forçará a VM a executar uma coleta de lixo". A TI da JVM faz parte da JavaDA Platform Debugger Architecture (JPDA) .
fonte
SIM , é quase possível forçar você a chamar métodos na mesma ordem e, ao mesmo tempo, são:
mesmo que seja apenas um objeto para limpar o uso desses dois métodos ao mesmo tempo, force o coletor de lixo a usar o
finalise()
método de objeto inacessível, liberando a memória atribuída e fazendo o que ofinalize()
método declara.No entanto , é uma péssima prática usar o coletor de lixo porque o uso dele pode introduzir uma sobrecarga no software que pode ser ainda pior do que na memória, o coletor de lixo tem seu próprio encadeamento que não é possível controlar mais, dependendo da o algoritmo usado pelo gc pode levar mais tempo e é considerado muito ineficiente; você deve verificar o seu software se for pior com a ajuda do gc, pois está definitivamente quebrado, uma boa solução não deve depender do gc.
NOTA: para ter em mente, isso funcionará apenas se no método finalizar não houver uma reatribuição do objeto; se isso acontecer, o objeto permanecerá vivo e haverá uma ressurreição tecnicamente possível.
fonte
gc()
é apenas uma dica para executar uma coleta de lixo.runFinalizers()
somente executa finalizadores em objetos "que foram encontrados como descartados". Se o gc não chegou a executar, pode haver nenhum desses objetos ...Sob a documentação de OutOfMemoryError , declara que não será lançada, a menos que a VM falhe ao recuperar a memória após uma coleta de lixo completa. Portanto, se você continuar alocando memória até obter o erro, já terá forçado uma coleta de lixo completa.
Presumivelmente, a pergunta que você realmente queria fazer era "como recuperar a memória que acho que deveria recuperar pela coleta de lixo?"
fonte
Para solicitar manualmente o GC (não do System.gc ()):
fonte
.gc é candidato à eliminação em versões futuras - um engenheiro da Sun comentou uma vez que talvez menos de vinte pessoas no mundo realmente sabem como usar .gc () - eu trabalhei ontem à noite por algumas horas em uma central / crítica estrutura de dados usando dados gerados pelo SecureRandom, em algum lugar além dos 40.000 objetos, a vm diminuiria a velocidade como se tivesse ficado sem ponteiros. Claramente, ele estava afogado em tabelas de ponteiros de 16 bits e exibia o comportamento clássico de "máquinas com falha".
Eu tentei -Xms e assim por diante, continuei mexendo um pouco até chegar a 57, xxx alguma coisa. Depois, o gc passaria de digamos 57.127 para 57.128 depois de um gc () - mais ou menos no ritmo do inchaço do código no campo Easy Money.
Seu design precisa de um retrabalho fundamental, provavelmente uma abordagem de janela deslizante.
fonte
Você pode acionar um GC na linha de comando. Isso é útil para batch / crontab:
Vejo :
fonte
A especificação da JVM não diz nada específico sobre coleta de lixo. Devido a isso, os fornecedores são livres para implementar o GC à sua maneira.
Portanto, essa imprecisão causa incerteza no comportamento da coleta de lixo. Você deve verificar os detalhes da JVM para conhecer as abordagens / algoritmos de coleta de lixo. Também há opções para personalizar o comportamento também.
fonte
Se você precisar forçar a coleta de lixo, talvez deva considerar como está gerenciando recursos. Você está criando objetos grandes que persistem na memória? Você está criando objetos grandes (por exemplo, classes de gráficos) que possuem uma
Disposable
interface e não chamamdispose()
quando terminam? Você está declarando algo em um nível de classe que você só precisa em um único método?fonte
Seria melhor se você descrevesse o motivo pelo qual você precisa de coleta de lixo. Se você estiver usando SWT, poderá dispor de recursos como
Image
eFont
para liberar memória. Por exemplo:Existem também ferramentas para determinar recursos não dispostos.
fonte
Se você está ficando sem memória e obtendo um,
OutOfMemoryException
pode tentar aumentar a quantidade de espaço de heap disponível para java iniciando o programa emjava -Xms128m -Xmx512m
vez de apenasjava
. Isso fornecerá um tamanho de pilha inicial de 128Mb e um máximo de 512Mb, que é muito mais do que os 32Mb / 128Mb padrão.fonte
java -Xms512M -Xmx1024M
Outra opção é não criar novos objetos.
O pool de objetos está ausente para reduzir a necessidade de GC em Java.
O pool de objetos geralmente não será mais rápido que a criação de objetos (especialmente para objetos leves), mas é mais rápido que a coleta de lixo. Se você criou 10.000 objetos e cada objeto tinha 16 bytes. São 160.000 bytes que o GC precisa recuperar. Por outro lado, se você não precisar de todos os 10.000 ao mesmo tempo, poderá criar um pool para reciclar / reutilizar os objetos, o que elimina a necessidade de construir novos objetos e elimina a necessidade de objetos antigos do GC.
Algo assim (não testado). E se você deseja que ele seja seguro para threads, você pode trocar o LinkedList por um ConcurrentLinkedQueue.
fonte
No OracleJDK 10 com G1 GC, uma única chamada
System.gc()
fará com que o GC limpe a coleção antiga. Não tenho certeza se o GC é executado imediatamente. No entanto, o GC não limpará a coleção Young, mesmo queSystem.gc()
seja chamado várias vezes em um loop. Para que o GC limpe a Coleção Jovem, você deve alocar em um loop (por exemplonew byte[1024]
) sem chamarSystem.gc()
. LigarSystem.gc()
por algum motivo impede que o GC limpe a Coleção Young.fonte
Isso está correto, apenas gesto. Você tem praticamente as respostas padrão já dadas por vários pôsteres. Vamos pegar um por um:
Correto, não existe jvm real - isso é apenas uma especificação, um monte de ciência da computação descrevendo o comportamento desejado ... Recentemente, procurei inicializar objetos Java a partir de código nativo. Para conseguir o que deseja, a única maneira é fazer o que é chamado de nulo agressivo. Os erros cometidos de maneira errada são tão ruins que precisamos nos limitar ao escopo original da pergunta:
A maioria dos pôsteres aqui assumirá que você está dizendo que está trabalhando em uma interface, caso seja necessário, teremos que verificar se você está recebendo o objeto inteiro ou um item de cada vez.
Se você não precisar mais de um objeto, poderá atribuir nulo ao objeto, mas se errar, será gerada uma exceção de ponteiro nulo. Aposto que você pode conseguir um trabalho melhor se usar o NIO
Sempre que você ou eu ou qualquer outra pessoa obtém: " Por favor, preciso disso horrivelmente. ", É quase um precursor quase universal da destruição quase total do que você está tentando trabalhar ... escreva-nos um pequeno código de exemplo, higienizando-o código real usado e nos mostre sua pergunta.
Não fique frustrado. Muitas vezes, o que isso resolve é que o seu dba está usando um pacote comprado em algum lugar e o design original não é aprimorado para estruturas de dados maciças.
Isso é muito comum.
fonte
Para sua informação
A chamada de método System.runFinalizersOnExit (true) garante que os métodos do finalizador sejam chamados antes que o Java seja encerrado. No entanto, esse método é inerentemente inseguro e foi preterido. Uma alternativa é adicionar "ganchos de desligamento" com o método Runtime.addShutdownHook.
Masarrat Siddiqui
fonte
Existe alguma maneira indireta de forçar o coletor de lixo. Você só precisa preencher a pilha com objetos temporários até o momento em que o coletor de lixo será executado. Eu criei uma classe que força o coletor de lixo desta maneira:
Uso:
Eu não sei o quanto esse método é útil, porque ele preenche a pilha constantemente, mas se você tiver um aplicativo de missão crítica que DEVE forçar o GC - quando essa pode ser a maneira portátil em Java de forçar o GC.
fonte
Eu gostaria de adicionar alguma coisa aqui. Por favor, não que o Java seja executado na Máquina Virtual e não na Máquina real. A máquina virtual possui seu próprio meio de comunicação com a máquina. Pode variar de sistema para sistema. Agora, quando chamamos o GC, pedimos à Máquina Virtual de Java que chame o Garbage Collector.
Como o Garbage Collector está com a Máquina Virtual, não podemos forçá-lo a fazer uma limpeza lá e depois. Em vez disso, enfileiramos nossa solicitação com o Garbage Collector. Depende da Máquina Virtual, após um determinado período de tempo (isso pode mudar de sistema para sistema, geralmente quando a memória de limite alocada para a JVM estiver cheia), a máquina real liberará o espaço. : D
fonte
O código a seguir é retirado do método assertGC (...). Ele tenta forçar o coletor de lixo não determinístico a coletar.
Fonte (adicionei alguns comentários para maior clareza): Exemplo NbTestCase
fonte
Você pode tentar usar
Runtime.getRuntime().gc()
ou usar o método utilitárioSystem.gc()
Nota: Esses métodos não garantem o GC. E seu escopo deve ser limitado à JVM em vez de manipulá-lo programaticamente em seu aplicativo.fonte
Se você estiver usando JUnit e Spring, tente adicionar isso em todas as classes de teste:
fonte