it-swarm-pt.tech

Quando o System.gc () faz alguma coisa?

Eu sei que a coleta de lixo é automatizada em Java. Mas entendi que, se você chamar System.gc() em seu código, a JVM pode ou não decidir executar a coleta de lixo nesse ponto. Como isso funciona precisamente? Em que base/parâmetros exatamente a JVM decide fazer (ou não) um GC quando vê System.gc()?

Há algum exemplo? Nesse caso, é uma boa ideia colocar isso no seu código?

109
harry

Na prática, normalmente = decide fazer uma coleta de lixo. A resposta varia dependendo de vários 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 no seu código. Se a JVM estiver prestes a lançar um OutOfMemoryError, chamar System.gc () não parará, porque o coletor de lixo tentará liberar o máximo possível antes de chegar ao extremo. A única vez que eu vi isso usado na prática é em IDEs, onde é anexado a um botão que um usuário pode clicar, mas mesmo assim não é muito útil.

57
jodonnell

O único exemplo em que posso pensar em como faz sentido chamar System.gc () é ao criar um perfil de um aplicativo para procurar possíveis vazamentos de memória. Eu acredito que os profilers chamam esse método antes de tirar uma foto da memória.

28
Guillermo Vasconcelos

Você não tem controle sobre GC em Java - o VM decide. Eu nunca encontrei um caso em que System.gc() seja necessário . Como uma chamada System.gc() simplesmente SUGERE que o VM faz uma coleta de lixo e também faz uma coleta de lixo COMPLETA (velhas e novas gerações em uma pilha multi-geracional), então pode realmente causar MORE cpu ciclos a serem consumidos do que o necessário.

Em alguns casos, pode fazer sentido sugerir ao VM que faça uma coleção completa AGORA, pois talvez você saiba que o aplicativo ficará ocioso pelos próximos minutos antes que ocorra um trabalho pesado. Por exemplo, logo após a inicialização de vários objetos temporários durante a inicialização do aplicativo (ou seja, eu coloquei em cache uma TON de informações e sei que não estarei recebendo muita atividade por um minuto ou mais). Pense em um IDE como o Eclipse iniciando - ele faz muito para inicializar, então talvez imediatamente após a inicialização faça sentido fazer um gc completo nesse ponto.

23
DustinB

O Java Language Specification não garante que a JVM inicie um GC quando você chamar System.gc(). Esta é a razão disso "pode ​​ou não decidir fazer um GC naquele momento".

Agora, se você olhar para código-fonte do OpenJDK , que é o backbone do Oracle JVM, você verá que uma chamada para System.gc() inicia um ciclo de GC. Se você usar outra JVM, como J9, precisará verificar a documentação para descobrir a resposta. Por exemplo, a JVM da Azul tem um coletor de lixo que é executado continuamente, então uma chamada para System.gc() não fará nada

Algumas outras respostas mencionam iniciar um GC no JConsole ou no VisualVM. Basicamente, essas ferramentas fazem uma chamada remota para System.gc().

Normalmente, você não quer iniciar um ciclo de coleta de lixo a partir do seu código, já que isso atrapalha 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 preocupações separadas (não faça seu aplicativo fazer algum gerenciamento de memória, foco nos negócios).

No entanto, há 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 ocorra no meio de um microbenchmark. Assim, você pode acionar um ciclo de GC entre cada medição para garantir que cada medição comece com um heap vazio.

22
Pierre Laporte

Você precisa ter muito cuidado se chamar System.gc(). Chamar isso pode adicionar problemas de desempenho desnecessários ao seu aplicativo, e não é garantido que ele realmente execute uma coleta. Na verdade, é possível desabilitar System.gc() explícito através do Java argumento -XX:+DisableExplicitGC.

Eu recomendo ler os documentos disponíveis em Java HotSpot Garbage Collection para detalhes mais detalhados sobre a coleta de lixo.

17
David Schlosnagle

System.gc() é implementado pela VM, e o que ele faz é específico da implementação. O implementador poderia simplesmente retornar e não fazer nada, por exemplo.

Quanto a quando emitir uma coleta manual, a única ocasião em que você pode querer fazer isso é quando você abandona uma grande coleção contendo cargas de coleções menores - um Map<String,<LinkedList>> por exemplo - e você quer tentar obter o resultado desejado. e lá, mas na maior parte, você não deve se preocupar com isso. O GC sabe melhor que você - infelizmente - na maior parte do tempo.

10
Patrick

Se você usar buffers de memória direta, a JVM não executará o GC para você, mesmo se estiver com pouca memória direta.

Se você chamar ByteBuffer.allocateDirect() e receber um OutOfMemoryError, verá que esta chamada está correta depois de disparar um GC manualmente.

8
Peter Lawrey

A maioria das JVMs inicia um GC (dependendo da opção -XX: DiableExplicitGC e -XX: + ExplicitGCInvokesConcurrent). Mas a especificação é apenas menos bem definida para permitir implementações melhores mais tarde.

A especificação precisa de esclarecimento: Bug # 6668279: (spec) System.gc () deve indicar que não recomendamos o uso e não garante comportamento

Internamente, o método gc é usado pelo RMI e pelo NIO, e eles requerem execução síncrona, o que: isto está atualmente em discussão:

Bug # 5025281: Permitir que System.gc () acione coleções completas simultâneas (não pare o mundo

4
eckes

Garbage Collection é bom em Java, se estivermos executando o software codificado em Java no Desktop/laptop/server. Você pode chamar System.gc() ou Runtime.getRuntime().gc() em Java.

Apenas observe que nenhuma dessas chamadas tem garantia de fazer nada. Eles são apenas uma sugestão para o jvm executar o Garbage Collector. Cabe a JVM se ele roda o GC ou não. Então, resposta curta: não sabemos quando é executado. Resposta mais longa: a JVM executaria o gc se tivesse tempo para isso.

Acredito que o mesmo se aplica ao Android. No entanto, isso pode desacelerar seu sistema.

2
Naveen

Normalmente, o VM faria uma coleta de lixo automaticamente antes de lançar um OutOfMemoryException, portanto, adicionar uma chamada explícita não deveria ajudar, exceto pelo fato de que talvez aumente o desempenho para um momento anterior.

No entanto, acho que encontrei um caso em que poderia ser relevante. Não tenho certeza, pois ainda tenho que testar se isso tem algum efeito:

Quando você mapeia a memória em um arquivo, acredito que a chamada map () lança uma IOException quando um bloco de memória grande o suficiente não estiver disponível. Uma coleta de lixo logo antes do arquivo map () pode ajudar a evitar isso, eu acho. O que você acha?

2
Vashek

nós nunca podemos forçar a coleta de lixo. System.gc está sugerindo apenas vm para coleta de lixo, no entanto, na verdade, a que horas o mecanismo é executado, ninguém sabe, isso é declarado pelas especificações JSR.

2
lwpro2

Há muito a ser dito em tomar o tempo para testar as várias configurações de coleta de lixo, mas como foi mencionado acima, geralmente não é útil fazê-lo.

No momento, estou trabalhando em um projeto envolvendo um ambiente limitado por memória e uma quantidade relativamente grande de dados - há alguns dados grandes que levam o meu ambiente ao limite e, mesmo assim, consegui reduzir o uso de memória que, em teoria, ele deveria funcionar muito bem, eu ainda teria erros de espaço de heap - as opções detalhadas do GC mostravam que ele estava tentando coletar 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 mais, mas o suficiente.

Conseqüentemente, a única vez que meu aplicativo chama System.gc () é quando ele está prestes a inserir o segmento de código onde grandes buffers necessários para processar os dados serão alocados, e um teste na memória livre disponível indica que eu não estou garantido para tê-lo. Em particular, estou olhando para um ambiente de 1GB onde pelo menos 300MB é ocupado por dados estáticos, com a maioria dos dados não-estáticos sendo relacionados à execução, exceto quando os dados sendo processados ​​passam a ser de pelo menos 100-200 MB a fonte. Tudo faz parte de um processo de conversão automática de dados, de modo que todos os dados existem por períodos relativamente curtos de tempo a longo prazo.

Infelizmente, enquanto a informação sobre as várias opções para ajustar o coletor de lixo está disponível, parece em grande parte um processo experimental e os detalhes de nível inferior necessários para entender como lidar com essas situações específicas não são facilmente obtidos.

Tudo isso dito, 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 da minha aplicação em uma quantidade relativamente significativa, apesar de ser incapaz de superar o obstáculo colocado por trabalhar com os maiores blocos 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 você a usa, você desejará que ela não funcionasse mais frequentemente do que não.

2
Kyune

Em resumo:

Parâmetros é VM dependente.

Exemplo de uso - não é possível pensar em um para aplicativos de tempo de execução/produção, mas é útil executá-lo para alguns chicotes de perfil, como chamar

// test run #1
test();
for (int i=0; i<10; i++) { 
// calling repeatedly to increase chances of a clean-up
  System.gc(); 
}
// test run #2
test();
1
mataal

Se você quiser saber se sua System.gc() é chamada, você pode com a nova Java 7 update 4 receber uma notificação quando a JVM executar Garbage Collection.

Não tenho 100% de certeza de que a classe GarbageCollectorMXBean foi introduzida no Java 7 update 4, porque não consegui encontrá-la nas notas de lançamento, mas achei as informações em o site javaperformancetuning . com

1
Shervin Asgari

De acordo com Thinking in Java de Bruce Eckel, um caso de uso para chamada explícita System.gc () é quando você quer forçar a finalização, i.n. a chamada para o método finalize.

0
Asterisk

Não consigo pensar em um exemplo específico quando é bom executar o GC explícito.

Em geral, executar o GC explícito pode realmente causar mais danos do que benefícios, porque um gc explícito acionará uma coleção completa, o que leva muito mais tempo à medida que passa por todos os objetos. Se esse gc explícito acabar sendo chamado repetidamente, poderia facilmente levar a um aplicativo lento, já que muito tempo é gasto na execução de GCs completos.

Alternativamente, se passar por cima do heap com um analisador de heap e suspeitar que um componente de biblioteca esteja chamando GCs explícitos, você poderá desativá-lo, adicionando: gc = -XX: + DisableExplicitGC aos parâmetros da JVM.

0
zxcv

enquanto system.gc funciona, ele irá parar o mundo: todas as respostas são interrompidas, então o coletor de lixo pode varrer cada objeto para verificar se é necessário deletá-lo. Se o aplicativo for um projeto da web, todas as solicitações serão interrompidas até que gc termine, e isso fará com que seu projeto da web não funcione em um único local.

0
fleture