Eu sei que a coleta de lixo é automatizada em Java. Mas eu entendi que se você chamar System.gc()
seu código, a JVM pode ou não decidir realizar a coleta de lixo naquele ponto. Como isso funciona exatamente? Em que base / parâmetros exatamente a JVM decide fazer (ou não fazer) um GC quando vê System.gc()
?
Há algum exemplo em que é uma boa ideia colocar isso em seu código?
java
garbage-collection
Michael
fonte
fonte
Respostas:
Na prática, geralmente decide fazer uma coleta de lixo. A resposta varia dependendo de muitos fatores, como em qual JVM você está executando, em qual modo está e qual algoritmo de coleta de lixo está usando.
Eu não dependeria disso em seu código. Se a JVM estiver prestes a lançar um OutOfMemoryError, chamar System.gc () não o parará, porque o coletor de lixo tentará liberar o máximo que puder antes de chegar a esse extremo. A única vez que vi isso ser usado na prática é em IDEs, onde é anexado a um botão no qual o usuário pode clicar, mas mesmo aí não é muito útil.
fonte
System.gc()
enquanto estava em uma tela de carregamento de um videogame. Nesse ponto, eu realmente não me importaria se a chamada cancelasse tudo o que pudesse ou não fizesse nada. Eu, no entanto, preferiria que ele "se esforçasse para reciclar objetos não usados" durante a tela de carregamento, em vez de durante o jogo.O único exemplo que posso pensar em que faz sentido chamar System.gc () é ao criar o perfil de um aplicativo para pesquisar possíveis vazamentos de memória. Acredito que os criadores de perfil chamam esse método antes de fazer um instantâneo da memória.
fonte
A especificação da linguagem Java não garante que a JVM iniciará um GC quando você ligar
System.gc()
. Esta é a razão de que "pode ou não decidir fazer um GC naquele momento".Agora, se você olhar o código-fonte do OpenJDK , que é o backbone do Oracle JVM, verá que uma chamada para
System.gc()
inicia um ciclo de GC. Se você usa outra JVM, como J9, você deve verificar sua documentação para descobrir a resposta. Por exemplo, a JVM da Azul tem um coletor de lixo que roda continuamente, então uma chamada paraSystem.gc()
não fará nadaAlgumas outras respostas mencionam o início de um GC no JConsole ou VisualVM. Basicamente, essas ferramentas fazem uma chamada remota para
System.gc()
.Normalmente, você não deseja iniciar um ciclo de coleta de lixo do seu código, pois isso bagunça a semântica do seu aplicativo. Seu aplicativo faz algumas coisas de negócios, a JVM cuida do gerenciamento de memória. Você deve manter essas questões separadas (não faça seu aplicativo fazer algum gerenciamento de memória, concentre-se nos negócios).
No entanto, existem alguns casos em que uma chamada para
System.gc()
pode ser compreensível. Considere, por exemplo, microbenchmarks. Ninguém quer que um ciclo de GC aconteça no meio de um microbenchmark. Portanto, você pode acionar um ciclo de GC entre cada medição para garantir que cada medição comece com uma pilha vazia.fonte
Você não tem controle sobre GC em java - a VM decide. Nunca encontrei um caso em que
System.gc()
fosse necessário . Uma vez que umaSystem.gc()
chamada simplesmente SUGERE que a VM faça uma coleta de lixo e também uma coleta de lixo COMPLETA (gerações antigas e novas em um heap multigeracional), ela pode, na verdade, fazer com que MAIS ciclos de CPU sejam consumidos do que o necessário.Em alguns casos, pode fazer sentido sugerir à VM que faça uma coleta completa AGORA, pois você pode saber que o aplicativo ficará ocioso pelos próximos minutos antes de ocorrer um trabalho pesado. Por exemplo, logo após a inicialização de muitos objetos temporários durante a inicialização do aplicativo (ou seja, acabei de armazenar em cache TONELADAS de informações e sei que não terei muita atividade por um minuto ou mais). Pense em um IDE como o eclipse inicializando - ele faz muito para inicializar, então talvez imediatamente após a inicialização faça sentido fazer um gc completo naquele ponto.
fonte
Você precisa ter muito cuidado ao ligar
System.gc()
. Chamá-lo pode adicionar problemas de desempenho desnecessários ao seu aplicativo e não é garantido que realmente execute uma coleção. Na verdade, é possível desativar o explícitoSystem.gc()
por meio do argumento java-XX:+DisableExplicitGC
.Recomendo enfaticamente a leitura dos documentos disponíveis em Java HotSpot Garbage Collection para obter detalhes mais aprofundados sobre a coleta de lixo.
fonte
System.gc()
é implementado pela VM e o que faz é específico da implementação. O implementador poderia simplesmente retornar e não fazer nada, por exemplo.Quanto ao momento de emitir uma coleta manual, o único momento em que você pode querer fazer isso é quando você abandona uma grande coleção que contém um monte de coleções menores -
Map<String,<LinkedList>>
por exemplo - e deseja tentar obter o golpe de desempenho então e lá, mas na maior parte, você não deve se preocupar com isso. O GC sabe melhor do que você - infelizmente - na maioria das vezes.fonte
Se você usar buffers de memória direta, a JVM não executa o GC para você, mesmo se você estiver com pouca memória direta.
Se você chamar
ByteBuffer.allocateDirect()
e obtiver um OutOfMemoryError, poderá descobrir que esta chamada está bem após acionar um GC manualmente.fonte
Cleaners
qual a memória direta usa. ou seja, não é liberado pelo thread finalizador, pois pode ser muito lento. Mesmo assim, é possível obter um OOME se você estiver criando regiões de memória direta particularmente rápido. A solução é não fazer isso e reutilizar suas regiões de memória direta onde for possível.A maioria das JVMs iniciará um GC (dependendo do switch -XX: DiableExplicitGC e -XX: + ExplicitGCInvokesConcurrent). Mas a especificação é apenas menos bem definida para permitir implementações melhores posteriormente.
A especificação precisa de esclarecimento: Bug # 6668279: (spec) System.gc () deve indicar que não recomendamos o uso e não garantimos o comportamento
Internamente, o método gc é usado por RMI e NIO, e eles requerem execução síncrona, que: isso está atualmente em discussão:
Bug # 5025281: Permitir que System.gc () acione coleções completas simultâneas (não pare o mundo)
fonte
Garbage Collection
é bom emJava
, se estivermos executando software codificado em java em desktop / laptop / servidor. Você pode ligarSystem.gc()
ouRuntime.getRuntime().gc()
entrarJava
.Observe que nenhuma dessas chamadas tem garantia de efeito. Eles são apenas uma sugestão para o jvm executar o Coletor de Lixo. Depende do JVM se ele executa o GC ou não. Portanto, uma resposta curta: não sabemos quando é executado. Resposta mais longa: JVM executaria gc se tivesse tempo para isso.
Acredito que o mesmo se aplica ao Android. No entanto, isso pode tornar seu sistema mais lento.
fonte
Normalmente, a VM faria uma coleta de lixo automaticamente antes de lançar uma OutOfMemoryException, portanto, adicionar uma chamada explícita não deve ajudar, exceto pelo fato de que talvez mova o impacto de desempenho para um momento anterior no tempo.
No entanto, acho que encontrei um caso em que pode ser relevante. Não tenho certeza, pois ainda tenho que testar se tem algum efeito:
Quando você mapeia a memória de um arquivo, acredito que a chamada map () lança uma IOException quando um bloco de memória grande o suficiente não está disponível. Uma coleta de lixo antes do arquivo map () pode ajudar a prevenir isso, eu acho. O que você acha?
fonte
nunca podemos forçar a coleta de lixo. System.gc está apenas sugerindo vm para coleta de lixo, entretanto, realmente a que horas o mecanismo é executado, ninguém sabe, isso é como afirmado pelas especificações JSR.
fonte
Há MUITO a ser dito sobre reservar um tempo para testar as várias configurações de coleta de lixo, mas, como foi mencionado acima, geralmente não é útil fazer isso.
Atualmente, estou trabalhando em um projeto que envolve um ambiente de memória limitada e uma quantidade relativamente grande de dados - existem algumas grandes partes de dados que levam meu ambiente ao seu limite, e embora eu tenha conseguido reduzir o uso de memória de forma que, em teoria, deveria funcionar bem, eu ainda obteria erros de espaço de heap --- as opções detalhadas do GC me mostraram que ele estava tentando coletar o lixo, mas sem sucesso. No depurador, eu poderia executar System.gc () e com certeza haveria "abundância" de memória disponível ... não muito extra, mas o suficiente.
Consequentemente, a única vez que meu aplicativo chama System.gc () é quando está prestes a inserir o segmento de código onde grandes buffers necessários para o processamento dos dados serão alocados e um teste na memória livre disponível indica que não estou garantido tê-lo. Em particular, estou olhando para um ambiente de 1 GB onde pelo menos 300 MB são ocupados por dados estáticos, com a maior parte dos dados não estáticos relacionados à execução, exceto quando os dados sendo processados são de pelo menos 100-200 MB em a fonte. Tudo faz parte de um processo de conversão automática de dados, portanto, todos os dados existem por períodos relativamente curtos de tempo no longo prazo.
Infelizmente, embora as informações sobre as várias opções para ajustar o coletor de lixo estejam disponíveis, parece um processo amplamente experimental e as especificações de nível inferior necessárias para entender como lidar com essas situações específicas não são facilmente obtidas.
Dito tudo isso, embora eu esteja usando System.gc (), eu ainda continuei a ajustar usando parâmetros de linha de comando e consegui melhorar o tempo de processamento geral do meu aplicativo em uma quantidade relativamente significativa, apesar de ser incapaz de superar o obstáculo representado pelo trabalho com os blocos maiores de dados. Dito isto, System.gc () é uma ferramenta .... uma ferramenta muito pouco confiável, e se você não for cuidadoso com a forma como a usa, vai desejar que não funcione com mais freqüência.
fonte
Se você quiser saber se o seu
System.gc()
é chamado, você pode, com a nova atualização 4 do Java 7, receber uma notificação quando a JVM executar a coleta de lixo.Não estou 100% certo de que a classe GarbageCollectorMXBean foi introduzida na atualização 4 do Java 7, porque não consegui encontrá-la nas notas de lançamento, mas encontrei as informações no site javaperformancetuning .com
fonte
Não consigo pensar em um exemplo específico em que seja bom executar o GC explícito.
Em geral, a execução de GC explícito pode realmente causar mais danos do que benefícios, porque um gc explícito acionará uma coleção completa, que leva muito mais tempo à medida que passa por cada objeto. Se esse gc explícito acabar sendo chamado repetidamente, pode facilmente levar a um aplicativo lento, pois muito tempo é gasto executando GCs completos.
Alternativamente, se estiver examinando o heap com um analisador de heap e você suspeitar que um componente da biblioteca está chamando GC explícito, você pode desativá-lo adicionando: gc = -XX: + DisableExplicitGC aos parâmetros JVM.
fonte
De acordo com o método Thinking in Java de Bruce Eckel, um caso de uso para uma chamada System.gc () explícita é quando você deseja forçar a finalização, ou seja, a chamada para o método finalize .
fonte
enquanto o system.gc funciona, ele irá parar o mundo: todas as respostas são interrompidas para que o coletor de lixo possa verificar cada objeto para verificar se é necessário excluí-lo. se o aplicativo for um projeto da web, todas as solicitações serão interrompidas até que o gc termine, e isso fará com que seu projeto da web não funcione em um momento.
fonte