Por que é uma prática ruim chamar System.gc ()?

326

Depois de responder a uma pergunta sobre como forçar a liberação de objetos em Java (o cara estava limpando um HashMap de 1,5 GB) System.gc(), me disseram que era uma prática ruim ligar System.gc()manualmente, mas os comentários não eram inteiramente convincentes. Além disso, ninguém parecia se atrever a votar, nem a minha resposta.

Foi-me dito lá que é uma má prática, mas também me disseram que as corridas de coletores de lixo não param sistematicamente mais o mundo, e que também poderia ser efetivamente usado pela JVM apenas como uma dica, então sou meio que em perda.

Entendo que a JVM geralmente sabe melhor que você quando precisa recuperar a memória. Eu também entendo que se preocupar com alguns kilobytes de dados é bobagem. Eu também entendo que mesmo megabytes de dados não é o que era há alguns anos atrás. Mas ainda assim, 1,5 gigabytes? E você sabe que existem 1,5 GB de dados na memória; não é como se fosse um tiro no escuro. É System.gc()sistematicamente ruim ou há algum momento em que tudo fica bem?

Portanto, a questão é realmente dupla:

  • Por que é ou não é uma prática ruim ligar System.gc()? É realmente apenas uma dica para a JVM sob certas implementações ou é sempre um ciclo de coleta completo? Existem implementações realmente de coletores de lixo que podem fazer seu trabalho sem parar o mundo? Por favor, mostre alguma luz sobre as várias afirmações que as pessoas fizeram nos comentários à minha resposta .
  • Onde está o limiar? É não uma boa idéia para chamar System.gc(), ou há momentos em que é aceitável? Se sim, quais são esses tempos?
zneak
fonte
4
Acho que um bom momento para chamar System.gc () é quando você está fazendo algo que já é um longo processo de carregamento. Por exemplo, estou trabalhando em um jogo e planejo chamar System.gc () quando o jogo carrega um novo nível, no final do processo de carregamento. O usuário já está esperando um pouco, e o aumento extra de desempenho pode valer a pena; mas também colocarei uma opção na tela de configuração para desativar esse comportamento.
Ricket 10/03/10
41
Bozho: observe a primeira palavra da pergunta. POR QUE é uma prática recomendada não chamá-lo? Apenas repetir um mantra não explica nada.
APENAS MINHA OPINIÃO correta
1
Outro caso foi explicado em java-monitor.com/forum/showthread.php?t=188 Onde ele explica como ele pode ser má prática para chamar o System.gc ()
Shirishkumar Bari

Respostas:

243

A razão pela qual todo mundo sempre diz para evitar System.gc()é que é um bom indicador de código fundamentalmente quebrado . Qualquer código que depende dele para correção está certamente quebrado; qualquer um que dependa disso para desempenho provavelmente está quebrado.

Você não sabe em que tipo de coletor de lixo está executando. Certamente existem alguns que não "param o mundo", como você afirma, mas algumas JVMs não são tão inteligentes ou por várias razões (talvez estejam ao telefone?) Não o fazem. Você não sabe o que vai fazer.

Além disso, não há garantia de fazer nada. A JVM pode apenas ignorar completamente sua solicitação.

A combinação de "você não sabe o que isso fará", "você não sabe se isso ajudará" e "você não precisa chamá-lo de qualquer maneira" é o motivo pelo qual as pessoas são tão enérgicas ao dizer que geralmente você não deveria chamá-lo. Eu acho que é um caso de "se você precisar perguntar se deveria usar isso, não deveria"


EDIT para abordar algumas preocupações do outro segmento:

Depois de ler o tópico que você vinculou, gostaria de destacar mais algumas coisas. Primeiro, alguém sugeriu que a chamada gc()pode retornar memória ao sistema. Isso certamente não é necessariamente verdade - o próprio heap Java cresce independentemente das alocações Java.

Assim, a JVM manterá a memória (muitas dezenas de megabytes) e aumentará a pilha conforme necessário. Não necessariamente retorna essa memória para o sistema, mesmo quando você libera objetos Java; é perfeitamente livre manter a memória alocada para uso em futuras alocações Java.

Para mostrar que é possível que System.gc()nada faça, veja:

http://bugs.sun.com/view_bug.do?bug_id=6668279

e, em particular, há uma opção -XX: DisableExplicitGC VM.

Steven Schlansker
fonte
1
Você pode criar uma configuração estranha ao estilo de Rube Goldberg, onde o método em que o GC é executado afeta a correção do seu código. Talvez esteja ocultando alguma interação estranha de encadeamento, ou talvez um finalizador tenha um efeito significativo na execução do programa. Não tenho certeza absoluta de que seja possível, mas pode ser, então pensei em mencionar.
Steven Schlansker
2
@zneak que você pode, por exemplo, ter colocado o código crítico em finalizadores (que é fundamentalmente quebrado código)
Martin
3
Eu gostaria de acrescentar que há alguns casos de canto em que System.gc()é útil e pode até ser necessário. Por exemplo, em aplicativos de interface do usuário no Windows, ele pode acelerar bastante o processo de restauração de uma janela quando você chama System.gc () antes de minimizar a janela (especialmente quando ela fica minimizada por um bom tempo e partes do processo são trocadas por disco).
Joachim Sauer
2
@AndrewJanke Eu diria que o código que usa WeakReferences para objetos nos quais você deseja se apegar está incorreto desde o início, coleta de lixo ou não. Você teria o mesmo problema em C ++ com std::weak_ptr(embora você possa notar o problema em uma versão C ++ mais cedo do que em uma versão Java, pois a destruição de objetos não seria adiada como a finalização geralmente é).
JAB
2
@rebeccah Isso é um bug, então sim, eu chamaria de 'certamente quebrado'. O fato de System.gc()corrigi-lo é uma solução alternativa, não é uma boa prática de codificação.
Steven Schlansker
149

Já foi explicado que a chamada system.gc() pode não fazer nada e que qualquer código que "precise" do coletor de lixo para executar está quebrado.

No entanto, o motivo pragmático pelo qual é uma prática ruim chamar System.gc()é de ser ineficiente. E no pior dos casos, é terrivelmente ineficiente ! Deixe-me explicar.

Um algoritmo de GC típico identifica lixo atravessando todos os objetos que não são lixo na pilha e inferindo que qualquer objeto não visitado deve ser lixo. A partir disso, podemos modelar o trabalho total de uma coleta de lixo consiste em uma parte que é proporcional à quantidade de dados ativos e outra parte que é proporcional à quantidade de lixo; ie work = (live * W1 + garbage * W2).

Agora, suponha que você faça o seguinte em um aplicativo de thread único.

System.gc(); System.gc();

A primeira chamada (prevemos) (live * W1 + garbage * W2)funcionará e se livrará do lixo pendente.

A segunda chamada (live* W1 + 0 * W2)funcionará e não recuperará nada. Em outras palavras, fizemos um (live * W1)trabalho e não conseguimos absolutamente nada .

Podemos modelar a eficiência do coletor como a quantidade de trabalho necessária para coletar uma unidade de lixo; ie efficiency = (live * W1 + garbage * W2) / garbage. Portanto, para tornar o GC o mais eficiente possível, precisamos maximizar o valor de garbagequando o rodamos; ou seja, aguarde até que a pilha esteja cheia. (E também, torne a pilha o maior possível. Mas esse é um tópico separado.)

Se o aplicativo não interferir (chamando System.gc()), o GC aguardará até que o heap esteja cheio antes de executar, resultando em uma coleta eficiente de lixo 1 . Mas se o aplicativo forçar a execução do GC, as chances são de que o heap não fique cheio e o resultado será que o lixo será coletado ineficientemente. E quanto mais a aplicação força o GC, mais ineficiente o GC se torna.

Nota: a explicação acima encobre o fato de que um GC moderno típico particiona o heap em "espaços", o GC pode expandir dinamicamente o heap, o conjunto de trabalho de objetos que não são lixo do aplicativo pode variar e assim por diante. Mesmo assim, o mesmo princípio básico se aplica a todos os verdadeiros coletores de lixo 2 . É ineficiente forçar o GC a funcionar.


1 - É assim que o coletor de "taxa de transferência" funciona. Coletores simultâneos, como CMS e G1, usam critérios diferentes para decidir quando iniciar o coletor de lixo.

2 - Também estou excluindo gerenciadores de memória que usam exclusivamente contagem de referência, mas nenhuma implementação Java atual usa essa abordagem ... por um bom motivo.

Stephen C
fonte
45
+1 boa explicação. Observe, porém, que esse raciocínio se aplica apenas se você se preocupa com a taxa de transferência. Se você deseja otimizar a latência em pontos específicos, forçar o GC pode fazer sentido. Por exemplo (hipoteticamente falando) em um jogo, você pode evitar atrasos durante os níveis, mas não se importa com atrasos durante a carga de nível. Então faria sentido forçar o GC após a carga nivelada. Isso diminui o rendimento geral, mas não é isso que você está otimizando.
precisa saber é o seguinte
2
@lesleske - o que você diz é verdade. No entanto, executar o GC entre níveis é uma solução de band-aid ... e não resolve o problema de latência se os níveis demorarem o suficiente para que você precise executar o GC durante um nível de qualquer maneira. Uma abordagem melhor é usar um coletor de lixo simultâneo (baixa pausa) ... se a plataforma suportar.
Stephen C
Não sabe ao certo o que você quer dizer com "precisa que o coletor de lixo seja executado". As condições que os aplicativos precisam evitar são; falhas de alocação que nunca podem ser satisfeitas e alta sobrecarga do GC. Fazer chamadas aleatoriamente para System.gc () geralmente resulta em alta sobrecarga do GC.
Kirk
@Kirk - "Fazer chamadas aleatoriamente para System.gc () geralmente resulta em alta sobrecarga do GC". . Eu sei disso. Assim como qualquer um que tivesse lido e compreendido a minha resposta.
Stephen C
@ Kirk - "Não tenho muita certeza do que você quer dizer ..." - quero dizer programas em que o comportamento "correto" de um programa depende da execução do GC em um determinado momento; por exemplo, para executar finalizadores ou interromper WeakReferences ou SoftReferences. É uma péssima idéia fazer isso ... mas é sobre isso que estou falando. Veja também a resposta de Steven Schlansker.
Stephen C
47

Parece que muitas pessoas estão dizendo para você não fazer isso. Discordo. Se, após um grande processo de carregamento, como carregar um nível, você acredita que:

  1. Você tem muitos objetos inacessíveis e que podem não ter sido controlados. e
  2. Você acha que o usuário poderia suportar uma pequena desaceleração neste momento

não há mal em chamar System.gc (). Eu olho para ele como a inlinepalavra-chave c / c ++ . É apenas uma dica para o gc de que você, o desenvolvedor, decidiu que o tempo / desempenho não é tão importante quanto costuma ser e que alguns deles podem ser usados ​​para recuperar a memória.

O conselho para não confiar nisso é que está fazendo tudo certo. Não confie em que ele funcione, mas dar a dica de que agora é um momento aceitável para coletar é perfeitamente aceitável. Prefiro perder tempo em um ponto do código em que isso não importa (tela de carregamento) do que quando o usuário está interagindo ativamente com o programa (como durante o nível de um jogo).

Há um momento em que forçarei a coleta: ao tentar descobrir, há um objeto específico vazando (código nativo ou interação grande e complexa de retorno de chamada. Ah, e qualquer componente da interface do usuário que olhe para o Matlab.) Isso nunca deve ser usado no código de produção.

KitsuneYMG
fonte
3
+1 para o GC durante a análise de vazamentos de mem. Observe que as informações sobre o uso de heap (Runtime.freeMemory () et al.) São realmente significativas apenas depois de forçar um GC, caso contrário, isso dependeria de quando o sistema se deu ao trabalho de executar um GC pela última vez.
precisa saber é o seguinte
4
não há mal nenhum em chamar System.gc () pode-se exigir stop the worldabordagem e este é um verdadeiro dano, se acontece
bestsss
7
é mal em chamar o coletor de lixo de forma explícita. Ligar para o GC na hora errada desperdiça ciclos da CPU. Você (o programador) não possui informações suficientes para determinar quando é a hora certa ... mas a JVM possui.
Stephen C
O Jetty faz 2 chamadas para System.gc () após a inicialização e raramente vi fazer alguma diferença.
Kirk
Bem, os desenvolvedores do Jetty têm um bug. Faria diferença ... mesmo que seja difícil quantificar a diferença.
Stephen C
31

As pessoas têm feito um bom trabalho explicando por que NÃO usar, então vou lhe dizer algumas situações em que você deve usá-lo:

(Os comentários a seguir se aplicam ao Hotspot em execução no Linux com o coletor CMS, onde me sinto confiante em dizer que System.gc(), na verdade, sempre invoca uma coleta de lixo completa).

  1. Após o trabalho inicial de inicialização do aplicativo, você pode estar com um estado terrível de uso da memória. Metade da sua geração assegurada pode estar cheia de lixo, o que significa que você está muito mais próximo do seu primeiro CMS. Nos aplicativos onde isso importa, não é uma má idéia chamar System.gc () para "redefinir" seu heap para o estado inicial dos dados ativos.

  2. Na mesma linha que o nº 1, se você monitorar seu uso de heap de perto, deseja ter uma leitura precisa do uso de memória de linha de base. Se os primeiros 2 minutos de tempo de atividade do seu aplicativo forem todos de inicialização, seus dados serão confundidos, a menos que você force (ahem ... "sugira") todo o código inicial.

  3. Você pode ter um aplicativo projetado para nunca promover nada para a geração ocupada enquanto ela estiver em execução. Mas talvez você precise inicializar alguns dados iniciais que não sejam tão grandes que sejam movidos automaticamente para a geração de propriedade. A menos que você chame System.gc () depois que tudo estiver configurado, seus dados poderão ficar na nova geração até chegar a hora de serem promovidos. De repente, seu aplicativo super-duper de baixa latência e baixo GC é atingido com uma penalidade de latência ENORME (relativamente falando, é claro) por promover esses objetos durante operações normais.

  4. Às vezes, é útil ter uma chamada System.gc disponível em um aplicativo de produção para verificar a existência de um vazamento de memória. Se você souber que o conjunto de dados ativos no tempo X deve existir em uma determinada proporção do conjunto de dados ativos no tempo Y, pode ser útil chamar System.gc () como tempo X e tempo Y e comparar o uso da memória .

JT.
fonte
1
Para a maioria dos coletores de lixo geracionais, os objetos da nova geração precisam sobreviver a um certo número (muitas vezes configurável) de coletas de lixo, portanto, chamar System.gc()uma vez para forçar a promoção de objetos não ganha nada. E você certamente não quer ligar System.gc()oito vezes seguidas e orar para que agora a promoção tenha sido feita e os custos salvos de uma promoção posterior justifiquem os custos de vários GCs completos. Dependendo do algoritmo do GC, a promoção de muitos objetos pode até não suportar custos reais, pois apenas reatribuirá a memória à geração antiga ou copia simultaneamente ...
Holger
11

Essa é uma pergunta muito incômoda, e eu sinto que contribui para muitos se oporem ao Java, apesar da utilidade de uma linguagem.

O fato de você não poder confiar no "System.gc" para fazer qualquer coisa é incrivelmente assustador e pode facilmente invocar o "medo, incerteza, dúvida" no idioma.

Em muitos casos, é bom lidar com picos de memória que você causa de propósito antes que ocorra um evento importante, o que levaria os usuários a pensar que seu programa foi mal projetado / não respondeu.

Ter capacidade de controlar a coleta de lixo seria uma ótima ferramenta educacional, melhorando a compreensão das pessoas sobre como a coleta de lixo funciona e como fazer com que os programas explorem seu comportamento padrão e também um comportamento controlado.

Deixe-me revisar os argumentos deste tópico.

  1. É ineficiente:

Muitas vezes, o programa pode não estar fazendo nada e você sabe que não está fazendo nada por causa da maneira como foi projetado. Por exemplo, pode estar fazendo algum tipo de espera longa com uma grande caixa de mensagem de espera e, no final, também pode adicionar uma chamada para coletar lixo, porque o tempo de execução levará uma fração muito pequena do tempo do longa espera, mas evitará que o gc atue no meio de uma operação mais importante.

  1. É sempre uma prática ruim e indica código quebrado.

Eu discordo, não importa qual coletor de lixo você tenha. Seu trabalho é rastrear o lixo e limpá-lo.

Ao chamar o gc durante os períodos em que o uso é menos crítico, você reduz as chances de ele funcionar quando sua vida depende do código específico que está sendo executado, mas decide coletar lixo.

Claro, pode não se comportar da maneira que você deseja ou espera, mas quando você deseja chamá-lo, sabe que nada está acontecendo e o usuário está disposto a tolerar lentidão / tempo de inatividade. Se o System.gc funcionar, ótimo! Se não, pelo menos você tentou. Simplesmente não há desvantagens, a menos que o coletor de lixo tenha efeitos colaterais inerentes que fazem algo terrivelmente inesperado ao modo como um coletor de lixo deve se comportar se chamado manualmente, e isso por si só causa desconfiança.

  1. Não é um caso de uso comum:

É um caso de uso que não pode ser alcançado com segurança, mas pode ser se o sistema foi projetado dessa maneira. É como criar um semáforo e fazê-lo para que alguns / todos os botões dos semáforos não façam nada, faz você questionar por que o botão está lá para começar, o javascript não tem a função de coleta de lixo, portanto examiná-lo tanto por isso.

  1. A especificação diz que System.gc () é uma dica de que o GC deve ser executado e a VM está livre para ignorá-lo.

o que é uma "dica"? o que é "ignorar"? se um computador não pode simplesmente dar dicas ou ignorar algo, existem caminhos rígidos de comportamento que podem ser dinâmicos, guiados pela intenção do sistema. Uma resposta adequada incluiria o que o coletor de lixo está realmente fazendo, no nível da implementação, que faz com que ele não execute a coleta quando você o solicita. O recurso é simplesmente um nop? Existe algum tipo de condição que eu devo atender? Quais são essas condições?

Tal como está, o GC de Java geralmente parece um monstro em que você simplesmente não confia. Você não sabe quando vai chegar ou vai, não sabe o que vai fazer, como vai fazer. Eu posso imaginar alguns especialistas tendo uma idéia melhor de como a coleta de lixo funciona por instrução, mas a grande maioria simplesmente espera que "simplesmente funcione", e ter que confiar em um algoritmo de aparência opaca para fazer o trabalho é frustrante.

Há uma grande lacuna entre ler sobre algo ou aprender algo, e realmente ver a implementação, as diferenças entre os sistemas e poder brincar com ele sem precisar olhar o código-fonte. Isso cria confiança e sentimento de domínio / compreensão / controle.

Para resumir, há um problema inerente às respostas "esse recurso pode não fazer nada, e não entrarei em detalhes como saber quando ele faz alguma coisa e quando não faz e por que não faz ou fará, muitas vezes implicando que é simplesmente contra a filosofia tentar fazê-lo, mesmo que a intenção por trás disso seja razoável ".

Pode ser aceitável que o Java GC se comporte da maneira que faz, ou não, mas, para entendê-lo, é difícil seguir verdadeiramente em que direção seguir para obter uma visão abrangente do que você pode confiar no GC e não fazer, por isso é muito fácil simplesmente desconfiar da linguagem, porque o objetivo de uma linguagem é ter um comportamento controlado até uma extensão filosófica (é fácil para um programador, especialmente iniciantes, entrar em crise existencial devido a certos comportamentos de sistema / linguagem). são capazes de tolerar (e se você não puder, você não usará o idioma até precisar), e mais coisas que você não pode controlar por nenhuma razão conhecida pela qual você não pode controlá-lo é inerentemente prejudicial.

Dmitry
fonte
9

A eficiência do GC depende de várias heurísticas. Por exemplo, uma heurística comum é que o acesso de gravação a objetos geralmente ocorre em objetos que foram criados há pouco tempo. Outra é que muitos objetos têm vida útil muito curta (alguns serão usados ​​por muito tempo, mas muitos serão descartados alguns microssegundos após sua criação).

Ligar System.gc()é como chutar o GC. Significa: "todos esses parâmetros cuidadosamente ajustados, essas organizações inteligentes, todo o esforço que você coloca para alocar e gerenciar os objetos de forma que as coisas corram bem, bem, basta largar o lote inteiro e começar do zero". Ele pode melhorar o desempenho, mas na maioria das vezes ele só degrada o desempenho.

Para usar de System.gc()forma confiável (*), você precisa saber como o GC opera em todos os detalhes. Esses detalhes tendem a mudar bastante se você usar uma JVM de outro fornecedor, ou a próxima versão do mesmo fornecedor ou a mesma JVM, mas com opções de linha de comando ligeiramente diferentes. Portanto, raramente é uma boa ideia, a menos que você queira resolver um problema específico no qual controla todos esses parâmetros. Daí a noção de "má prática": isso não é proibido, o método existe, mas raramente compensa.

(*) Estou falando de eficiência aqui. System.gc()nunca interromperá um programa Java correto. Ele também não evocará memória extra que a JVM não poderia ter obtido de outra maneira: antes de lançar um OutOfMemoryError, a JVM fará o trabalho System.gc(), mesmo que como último recurso.

Thomas Pornin
fonte
1
+1 por mencionar que System.gc () não impede OutOfMemoryError. Algumas pessoas acreditam nisso.
sleske
1
Na verdade, isso pode impedir o OutOfMemoryError devido ao tratamento de referências suaves. As SoftReferences criadas após a última execução do GC não são coletadas na implementação que eu conheço. Mas este é um detalhe da implementação sujeito a alterações a qualquer momento e uma espécie de bug e nada em que você deve confiar.
Maaartinus
8

Às vezes ( não com frequência! ), Você realmente sabe mais sobre o uso da memória passada, atual e futura do que o tempo de execução. Isso não acontece com muita frequência, e eu nunca afirmaria em um aplicativo Web enquanto páginas normais estão sendo veiculadas.

Há muitos anos, trabalho em um gerador de relatórios, que

  • Tinha um único segmento
  • Leia a "solicitação de relatório" de uma fila
  • Carregou os dados necessários para o relatório do banco de dados
  • Gerou o relatório e o enviou por e-mail.
  • Repetido para sempre, dormindo quando não havia pedidos pendentes.
  • Não reutilizou nenhum dado entre relatórios e não efetuou nenhum pagamento.

Primeiro, como não era em tempo real e os usuários esperavam esperar por um relatório, um atraso durante a execução do GC não era um problema, mas precisávamos produzir relatórios a uma taxa mais rápida do que o solicitado.

Olhando para o esboço acima do processo, é claro que.

  • Sabemos que haveria muito poucos objetos ativos logo após o envio de um relatório, pois a próxima solicitação ainda não havia sido processada.
  • É sabido que o custo de executar um ciclo de coleta de lixo depende do número de objetos ativos; a quantidade de lixo tem pouco efeito no custo de uma execução de GC.
  • Quando a fila estiver vazia, não há nada melhor para fazer do que executar o GC.

Portanto, claramente valia a pena executar uma GC sempre que a fila de solicitações estivesse vazia; não havia desvantagem nisso.

Pode valer a pena executar uma execução no GC após o envio de cada relatório, pois sabemos que este é um bom momento para uma execução no GC. No entanto, se o computador tivesse RAM suficiente, melhores resultados seriam obtidos atrasando a execução do GC.

Esse comportamento foi configurado por instalação, para alguns clientes que habilitaram um GC forçado depois que cada relatório acelerou bastante a proteção dos relatórios. (Eu espero que isso se deva à falta de memória no servidor e à execução de muitos outros processos; portanto, um GC forçado com tempo reduzido reduziu a paginação).

Nunca detectamos que uma instalação que não beneficiava era uma execução forçada de GC toda vez que a fila de trabalho estava vazia.

Mas, deixe claro, o exposto acima não é um caso comum.

Ian Ringrose
fonte
3

Talvez eu escreva códigos ruins, mas percebi que clicar no ícone da lixeira nos IDEs do eclipse e do netbeans é uma 'boa prática'.

Ryan Fernandes
fonte
1
Isso pode ser verdade. Mas se o Eclipse ou o NetBeans fosse programado para chamar System.gc()periodicamente, você provavelmente acharia o comportamento irritante.
Stephen C
2

Primeiro, há uma diferença entre especificação e realidade. A especificação diz que System.gc () é uma dica de que o GC deve ser executado e a VM está livre para ignorá-lo. A realidade é que a VM nunca ignorará uma chamada para System.gc ().

Ligar para o GC vem com uma sobrecarga não trivial para a ligação e, se você fizer isso em algum momento aleatório, provavelmente não verá recompensa por seus esforços. Por outro lado, é muito provável que uma cobrança acionada naturalmente recupere os custos da chamada. Se você tiver informações que indiquem que um GC deve ser executado, poderá telefonar para System.gc () e obter benefícios. No entanto, é minha experiência que isso acontece apenas em alguns casos extremos, pois é muito improvável que você tenha informações suficientes para entender se e quando System.gc () deve ser chamado.

Um exemplo listado aqui, atingindo a lata de lixo no seu IDE. Se você estiver indo para uma reunião, por que não acertar? A sobrecarga não afetará você e a pilha pode ser limpa para quando você voltar. Faça isso em um sistema de produção e as chamadas frequentes para coletar interromperão a moagem! Mesmo chamadas ocasionais, como as feitas pela RMI, podem prejudicar o desempenho.

Kirk
fonte
3
"A realidade é que a VM nunca ignorará uma chamada para System.gc ()." - Incorreta. Leia sobre -XX: -DisableExplicitGC.
Stephen C
1

Sim, chamar System.gc () não garante a execução, é uma solicitação à JVM que pode ser ignorada. Dos documentos:

Chamar o método gc sugere que a Java Virtual Machine gaste esforço para reciclar objetos não utilizados

É quase sempre uma má idéia chamá-lo, porque o gerenciamento automático de memória geralmente sabe melhor do que você quando se deve jogar. Isso será feito quando o pool interno de memória livre estiver baixo ou se o sistema operacional solicitar que alguma memória seja devolvida.

Pode ser aceitável chamar System.gc () se você souber que isso ajuda. Com isso, quero dizer que você testou e mediu completamente o comportamento de ambos os cenários na plataforma de implantação e pode mostrar que ajuda. Esteja ciente de que o GC não é facilmente previsível - pode ajudar em uma corrida e prejudicar em outra.

tom
fonte
<stroke> Mas também do Javadoc: _Quando o controle retorna da chamada do método, a máquina virtual se esforça ao máximo para reciclar todos os objetos descartados, o que considero uma forma mais imperativa do que você publicou. </ stroke > Dane-se isso, há um relatório de erro sobre isso ser enganoso. Como sabe melhor, quais são os malefícios de sugerir a JVM?
zneak
1
O dano é que fazer a coleta no momento errado pode ser uma grande desaceleração. A dica que você está dando é provavelmente ruim. Quanto ao comentário do "melhor esforço", tente e veja em uma ferramenta como o JConsole. Às vezes, clicar no botão "Executar GC" não faz nada
tom
Desculpe discordar, mas chamar System.gc () no OpenJDK e tudo o que é baseado nele (HP, por exemplo) sempre resulta em um ciclo de coleta de lixo. Na verdade isso parece verdadeiro de implementação J9 da IBM também
Kirk
@ Kirk - Incorreto: google e leia sobre -XX: -DisableExplicitGC.
Stephen C
0

Na minha experiência, usar System.gc () é efetivamente uma forma específica de otimização de plataforma (onde "plataforma" é a combinação de arquitetura de hardware, SO, versão da JVM e possíveis parâmetros de tempo de execução, como RAM disponível), porque seu comportamento, embora aproximadamente previsível em uma plataforma específica, pode (e irá) variar consideravelmente entre as plataformas.

Sim, existem são situações em que System.gc () irão melhorar o desempenho (percebido). Por exemplo, se atrasos são toleráveis ​​em algumas partes do seu aplicativo, mas não em outras (o exemplo do jogo citado acima, onde você deseja que o GC aconteça no início de um nível, não durante o nível).

No entanto, se isso ajudará ou prejudicará (ou não fará nada) depende muito da plataforma (conforme definido acima).

Portanto, acho que é válido como uma otimização específica da plataforma de último recurso (ou seja, se outras otimizações de desempenho não forem suficientes). Mas você nunca deve chamá-lo apenas porque acredita que isso pode ajudar (sem referências específicas), porque as chances são de que não ajudará.

sleske
fonte
0
  1. Como os objetos são alocados dinamicamente usando o novo operador,
    você pode estar se perguntando como esses objetos são destruídos e sua
    memória liberada para realocação posterior.

  2. Em algumas linguagens, como C ++, os objetos alocados dinamicamente devem ser liberados manualmente pelo uso de um operador de exclusão.

  3. Java adota uma abordagem diferente; ele lida com a desalocação automaticamente.
  4. A técnica que realiza isso é chamada de coleta de lixo. Funciona assim: quando não existem referências a um objeto, presume-se que ele não é mais necessário e a memória ocupada pelo objeto pode ser recuperada. Não há necessidade explícita de destruir objetos como no C ++.
  5. A coleta de lixo ocorre apenas esporadicamente (se houver) durante a execução do seu programa.
  6. Isso não ocorrerá simplesmente porque existe um ou mais objetos que não são mais usados.
  7. Além disso, diferentes implementações de tempo de execução Java terão abordagens variadas para a coleta de lixo, mas, na maioria das vezes, você não deve pensar nisso enquanto escreve seus programas.
Tanmay Delhikar
fonte