Pergunta

Depois de ler esta pergunta, Lembrei-me de quando eu era ensinado Java e disse nunca para chamar finalize() ou executar o coletor de lixo, porque "é uma grande caixa preta que você nunca precisa se preocupar".Alguém pode ferver o raciocínio para este para baixo algumas frases?Eu tenho certeza que eu poderia ler um relatório técnico do Sol sobre o assunto, mas eu acho uma boa, curto, simples resposta poderia satisfazer a minha curiosidade.

Foi útil?

Solução

A resposta curta:Java coleta de lixo é muito afinado ferramenta.Do sistema.gc() é um trenó-martelo.

Java heap é dividido em diferentes gerações, cada uma das quais são coletados usando uma estratégia diferente.Se você anexar um profiler para uma saudável aplicativo, você vai ver que é muito raramente tem para executar o mais caro tipos de coleções, porque a maioria dos objetos são capturados pela copiar com rapidez coletor na geração jovem.

O Sistema De Chamada.gc() diretamente, embora não seja tecnicamente garantido para fazer qualquer coisa, na prática, vai disparar um caro, pare-o-mundo cheio de pilha coleção.Este é quase sempre a coisa errada a fazer.Você acha que você é a economia de recursos, mas na verdade você está desperdiçando-los sem uma boa razão, forçando Java para verificar novamente todos os seus objetos vivos "just in case".

Se você está tendo problemas com o GC pausas em momentos críticos, é melhor configurar a JVM para uso simultâneo de marca/sweep coletor, que foi projetado especificamente para minimizar o tempo gasto em pausa, de tentar levar uma marreta para o problema e só quebra-lo ainda mais.

O Sol documento que você estava pensando aqui: Java SE 6 HotSpot™ Virtual Machine Coleta de Lixo Tuning

(Outra coisa que talvez você não saiba:a implementação de um método finalize() no objeto faz a coleta de lixo mais lento.Em primeiro lugar, vai demorar dois GC é executado para recolher o objeto:um para executar finalize() e o seguinte para garantir que o objeto não foi ressuscitado durante a sua finalização.Em segundo lugar, os objetos com finalize() métodos têm de ser tratados como casos especiais, pelo GC, porque eles têm de ser recolhidas individualmente, eles não podem simplesmente ser jogados fora em massa.)

Outras dicas

Não se preocupe com finalizadores.

Mudar para a recolha de lixo incremental.

Se você quiser ajudar o coletor de lixo, null fora de referências para objetos que já não necessita.Menos caminho a seguir= mais explicitamente lixo.

Não se esqueça de que (não estático) classe interna instâncias manter as referências a sua principal instância de classe.Assim, uma classe interna thread mantém muito mais bagagem que você pode esperar.

Muito relacionadas veia, se você estiver usando a serialização, e você já serializado objetos temporários, o que você vai precisar para limpar a serialização de caches, chamando ObjectOutputStream.reset() ou o seu processo de perda de memória e, eventualmente, morrer.Desvantagem é que os não-objetos transitórios estão indo para obter re-serializado.Serialização temporária de objetos de resultado pode ser um pouco mais confuso do que você imagina!

Considere o uso de soft referências.Se você não sabe o que macio referências são, têm uma leitura de o javadoc para a linguagem java.lang.ref.SoftReference

Orientar clara de Fantasma referências e referências Fracas, a menos que você realmente obter excitáveis.

Finalmente, se você realmente não pode tolerar o GC usar, em tempo real Java.

Não, eu não estou brincando.

A implementação de referência é gratuito para download e Pedro Dibbles livro do SOL é realmente boa leitura.

Na medida finalizadores ir:

  1. Eles são praticamente inúteis.Eles não são garantidos para ser chamada em tempo hábil, ou, de fato, em tudo (se o GC nunca é executado, nem qualquer finalizadores).Isso significa que você geralmente não deve confiar neles.
  2. Finalizadores não são garantidos para ser idempotentes.O coletor de lixo toma o maior cuidado para garantir que ele nunca vai chamar finalize() mais de uma vez sobre o mesmo objeto.Com bem escrito objetos, não importa, mas com mal-escrito objetos, chamando finalizar várias vezes pode causar problemas (e.g.duplo lançamento de um recurso nativo ...crash).
  3. Todos objeto que tem um finalize() o método também deve fornecer uma close() (ou similar) método.Esta é a função que deve ser chamada.por exemplo, FileInputStream.close().Não há nenhuma razão para ser chamado finalize() quando você tem um método mais adequado que é deve ser chamado por você.

Supondo que finalizadores são semelhantes aos seus .NET homônimo, em seguida, você só precisa realmente chamar esses quando tiver recursos, tais como identificadores de arquivo que pode vazar.A maior parte do tempo, seus objetos não têm estas referências, assim eles não precisam ser chamado.

É ruim para tentar recolher o lixo, porque não é realmente o seu lixo.Você disse a VM para alocar memória quando você criou objetos, e o coletor de lixo está escondendo informações sobre esses objetos.Internamente, o GC está realizando otimizações sobre as alocações de memória que faz.Quando você tentar manualmente para coletar o lixo você não tem nenhum conhecimento sobre o que o GC quer se apegar e livrar-se, você está apenas forçando a mão.Como resultado, você bagunça cálculos internos.

Se você soubesse mais sobre o que o GC estava segurando internamente, em seguida, você pode ser capaz de tomar decisões mais informadas, mas, em seguida, você já perdeu os benefícios da GC.

O verdadeiro problema com a fechar OS punhos em finalizar é que finalize são executados em nenhuma ordem garantida.Mas se você tem alças para as coisas que de bloco (e.g. pensarsockets) potencialmente, seu código pode ficar em situação de deadlock (não trivial em todos).

Então, eu estou explicitamente fechar os punhos em uma forma ordenada e previsível.Basicamente, o código para lidar com os recursos devem seguir o padrão:

SomeStream s = null;
...
try{
   s = openStream();
   ....
   s.io();
   ...
} finally {
   if (s != null) {
       s.close();
       s = null;
   }
}

Tudo fica ainda mais complicado se você escrever suas próprias classes que funcionam através de JNI e identificadores abertos.Você precisará certificar-se de alças estão fechadas (liberado) e que isso vai acontecer apenas uma vez.Freqüentemente negligenciado OS alça na área de Trabalho J2SE é Graphics[2D].Mesmo BufferedImage.getGrpahics() potencialmente pode retornar o identificador que aponta para um driver de vídeo (na verdade, mantendo o recurso GPU).Se você não o solte-se e deixe-o coletor de lixo para fazer o trabalho, você pode achar estranho OutOfMemory e iguais a situação quando você correu para fora da placa de vídeo mapeada bitmaps, mas ainda tem muita memória.Na minha experiência, isso acontece com freqüência em ciclos restritos trabalhando com objetos gráficos (extração de miniaturas, redimensionamento, a afiar o nome dele).

Basicamente GC não cuidar de programadores a responsabilidade da correcta gestão dos recursos.Ele só cuida de memória e nada mais.O Fluxo.finalize chamar close() IMHO, seria melhor aplicado jogando exceção novo RuntimeError("coleta de lixo a sequência que ainda está aberto").Ele vai economizar horas e dias de depuração e limpeza de código após o desleixado amadores esquerda extremidades perder.

Codificação feliz.

Paz.

O GC faz um monte de otimização em quando corretamente finalizar as coisas.

Assim, a menos que você esteja familiarizado com a forma como o GC funciona de fato e como ele tags gerações, chamar manualmente finalizar ou iniciar GC ing provavelmente irá afetar o desempenho de ajuda.

Evitar finalizadores.Não há nenhuma garantia de que eles serão chamados em tempo hábil.Ele pode levar um longo tempo antes que o sistema de Gerenciamento de Memória (por exemplo, o coletor de lixo) decide recolher um objeto com um finalizador.

Muitas pessoas usam finalizadores para fazer coisas como fechar conexões de soquete ou excluir arquivos temporários.Fazendo isso você faz a sua aplicação comportamento imprevisível e amarrado para quando a JVM vai GC o seu objeto.Isso pode levar a "falta de memória" cenários, não devido ao Java Heap sendo esgotados, mas sim devido ao sistema de execução de alças para um determinado recurso.

Uma outra coisa a ter em mente é que a introdução de chamadas de Sistema.gc() ou martelos podem mostrar bons resultados em seu ambiente, mas eles não se traduz necessariamente para outros sistemas.Nem todos tem a mesma JVM, há muitos, SUN, IBM J9, BEA JRockit, a Harmonia, o OpenJDK, etc...Este JVM todos estão de acordo com a JCK (aqueles que foram oficialmente testados que é), mas tem um monte de liberdade quando se trata de fazer as coisas rápido.GC é uma das áreas que todo mundo investe pesadamente.Usando um martelo muitas vezes destruir esse esforço.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top