Eu preciso saber quando o finalize()
método é chamado no JVM
. Eu criei uma classe de teste que grava em um arquivo quando o finalize()
método é chamado, substituindo-o. Não é executado. Alguém pode me dizer o motivo pelo qual não está sendo executado?
330
finalize()
e coleta de lixo não tem nenhum impacto.Respostas:
Em geral, é melhor não confiar
finalize()
para fazer qualquer limpeza, etc.De acordo com o Javadoc (que valeria a pena ler), é:
Como Joachim apontou, isso nunca pode acontecer na vida de um programa se o objeto estiver sempre acessível.
Além disso, não é garantido que o coletor de lixo seja executado em um momento específico. Em geral, o que estou tentando dizer é que
finalize()
provavelmente não é o melhor método para usar em geral, a menos que haja algo específico para o qual você precise.fonte
finalize
que seriam úteis?finalize()
método ativado para a classe principal é chamado quando uma instância >> da classe >> é coletada como lixo, não quando o método principal é finalizado. Além disso, a classe principal pode ser coletada como lixo antes do término do aplicativo; por exemplo, em um aplicativo multithread em que o thread "main" cria outros threads e depois retorna. (Na prática, um carregador de classes não-padrão seria necessário ....)O
finalize
método é chamado quando um objeto está prestes a receber o lixo coletado. Isso pode ocorrer a qualquer momento após se tornar elegível para a coleta de lixo.Observe que é perfeitamente possível que um objeto nunca seja coletado como lixo (e, portanto,
finalize
nunca é chamado). Isso pode acontecer quando o objeto nunca se torna elegível para o gc (porque é alcançável durante toda a vida útil da JVM) ou quando nenhuma coleta de lixo é executada entre o momento em que o objeto se torna elegível e o tempo em que a JVM para de ser executada (isso geralmente ocorre com programas de teste).Existem maneiras de dizer à JVM para executar
finalize
em objetos que ainda não foram chamados, mas usá-los também não é uma boa ideia (as garantias desse método também não são muito fortes).Se você confiar na
finalize
operação correta do seu aplicativo, estará fazendo algo errado.finalize
deve ser usado apenas para limpeza de recursos (geralmente não Java). E isso é exatamente porque a JVM não garante quefinalize
alguma vez seja chamada em qualquer objeto.fonte
Closable
interface (e a idéia por trás dela) é provavelmente o que você deseja:.close()
feche / descarte o recurso e exija que o usuário da sua classe o chame no momento certo. Você pode adicionar umfinalize
método "apenas para salvar", mas isso seria mais uma ferramenta de depuração do que uma correção real (porque não é confiável o suficiente).System.gc()
para chamar FileInputStream :: finalize (), para poder mover o arquivo.citado em: http://www.janeg.ca/scjp/gc/finalize.html
Você também pode verificar este artigo:
fonte
O
finalize()
método Java não é um destruidor e não deve ser usado para lidar com a lógica da qual seu aplicativo depende. A especificação Java afirma que não há garantia de que ofinalize
método seja chamado durante o tempo de vida do aplicativo.O que você provavelmente quer é uma combinação
finally
e um método de limpeza, como em:fonte
Confira o Effective Java, segunda edição, página 27. Item 7: Evite finalizadores
Para finalizar um recurso, use try-finalmente:
fonte
O método finalize será chamado depois que o GC detectar que o objeto não está mais acessível e antes de realmente recuperar a memória usada pelo objeto.
Se um objeto nunca se torna inacessível,
finalize()
nunca será chamado a ele.Se o GC não funcionar,
finalize()
nunca poderá ser chamado. (Normalmente, o GC é executado apenas quando a JVM decide que é provável que haja lixo suficiente para valer a pena.)Pode levar mais de um ciclo do GC antes que o GC determine que um objeto específico está inacessível. (Os GCs Java geralmente são coletores "geracionais" ...)
Depois que o GC detecta um objeto inacessível e finalizável, ele é colocado em uma fila de finalização. A finalização geralmente ocorre de forma assíncrona com o GC normal.
(Na verdade, a especificação da JVM permite que uma JVM nunca execute finalizadores ... desde que não recupere o espaço usado pelos objetos. Uma JVM implementada dessa maneira seria prejudicada / inútil, mas esse comportamento é "permitido" .)
O resultado é que não é prudente confiar na finalização para fazer as coisas que precisam ser feitas em um prazo definido. É uma "prática recomendada" não usá-los. Deve haver uma maneira melhor (ou seja, mais confiável) de fazer o que você está tentando fazer no
finalize()
método.O único uso legítimo para finalização é limpar os recursos associados aos objetos que foram perdidos pelo código do aplicativo. Mesmo assim, você deve tentar escrever o código do aplicativo para que ele não perca os objetos em primeiro lugar. (Por exemplo, use o Java 7+ try-with-resources para garantir que
close()
seja sempre chamado ...)É difícil dizer, mas existem algumas possibilidades:
fonte
Como existe uma incerteza na chamada do método finalize () pela JVM (não tenho certeza se finalize () substituído será executado ou não), para fins de estudo, a melhor maneira de observar o que acontece quando finalize () é chamado é forçar a JVM a chamar coleta de lixo por comando
System.gc()
.Especificamente, finalize () é chamado quando um objeto não está mais em uso. Mas quando tentamos chamá-lo criando novos objetos, não há certeza de sua chamada. Portanto, com certeza, criamos um
null
objetoc
que obviamente não tem uso futuro; portanto, vemos ac
chamada finalizada do objeto .Exemplo
Resultado
Nota - Mesmo depois de imprimir até 70 e após o qual o objeto b não está sendo usado no programa, há incerteza de que b seja limpo ou não pela JVM, pois "O método finalizado chamado na classe Bike ..." não é impresso.
fonte
System.gc();
não é uma garantia de que a coleta de lixo será realmente executada.finalize imprimirá a contagem para a criação da classe.
a Principal
Como você pode ver. O exemplo a seguir mostra que o gc foi executado pela primeira vez quando a contagem de turmas é 36.
fonte
Tendo lutado com os métodos do finalizador recentemente (para descartar pools de conexão durante o teste), devo dizer que falta ao finalizador muitas coisas. Usando o VisualVM para observar e usando referências fracas para rastrear a interação real, descobri que as seguintes coisas são verdadeiras em um ambiente Java 8 (Oracle JDK, Ubuntu 15):
Pensamento final
O método Finalize não é confiável, mas pode ser usado apenas para uma coisa. Você pode garantir que um objeto tenha sido fechado ou descartado antes da coleta de lixo, possibilitando a implementação de uma segurança contra falhas se objetos com um ciclo de vida mais complexo envolvendo uma ação de final de vida útil forem tratados corretamente. Essa é a única razão pela qual consigo pensar que faz valer a pena substituí-la.
fonte
Um Objeto torna-se elegível para coleta de lixo ou GC se não estiver acessível a partir de nenhum encadeamento ativo ou de referências estáticas em outras palavras, você pode dizer que um objeto se torna elegível para coleta de lixo se todas as suas referências forem nulas. As dependências cíclicas não são contadas como referência, portanto, se o Objeto A tiver referência ao objeto B e o objeto B tiver referência ao Objeto A e não tiverem outra referência ativa, os Objetos A e B serão elegíveis para a coleta de lixo. Geralmente, um objeto se torna elegível para coleta de lixo em Java nos seguintes casos:
fonte
final
campo de um objeto for usado repetidamente durante uma computação lenta, e o objeto nunca será usado depois disso, o objeto será mantido vivo até a última vez que o código-fonte solicitar o campo ou o JIT poderá copiá-lo para um variável temporária e depois abandonar o objeto antes da computação?GC.KeepAlive()
função que não faz nada, a não ser forçar o GC a assumir que ele pode usar um objeto, mas não conheço essa função em Java. Pode-se usarvolatile
variável para esse fim, mas o uso de uma variável exclusivamente para esse objetivo pareceria um desperdício.FinalizerReference
, para que ele não precise de um ciclo de GC para descobrir que não há referências. A sincronização é suficiente para garantir um relacionamento acontece antes ; como a finalização pode (na verdade está) sendo executada em um encadeamento diferente, geralmente é formalmente necessária de qualquer maneira. O Java 9 vai adicionarReference.reachabilityFence
…Finalize
seria chamado se o JIT produzisse o código que o fez diretamente. Normalmente, o código de sincronização é esperado para objetos que esperam ser usados apenas em um único encadeamento? Se um objeto executar alguma ação que precisa ser desfeita antes de ser abandonado (por exemplo, abrir uma conexão de soquete e adquirir uso exclusivo do recurso na outra extremidade), ter um finalizador fechando a conexão enquanto o código ainda estiver usando o soquete seria um desastre. . Seria normal que o código usasse a sincronização ... #O método finalize não é garantido. Esse método é chamado quando o objeto se torna elegível para o GC. Existem muitas situações em que os objetos podem não ser coletados como lixo.
fonte
Às vezes, quando é destruído, um objeto deve fazer uma ação. Por exemplo, se um objeto tiver um recurso não-java, como um identificador de arquivo ou uma fonte, você poderá verificar se esses recursos foram liberados antes de destruir um objeto. Para gerenciar essas situações, o java oferece um mecanismo chamado "finalização". Ao finalizá-lo, é possível definir ações específicas que ocorrem quando um objeto está para ser removido do coletor de lixo. Para adicionar um finalizador a uma classe, basta definir o método finalize () . O tempo de execução do Java chama esse método sempre que está prestes a excluir um objeto dessa classe. Dentro da finalização método ()você especifica ações a serem executadas antes de destruir um objeto. O coletor de lixo é pesquisado periodicamente por objetos que não se referem mais a nenhum estado em execução ou indiretamente a qualquer outro objeto com referência. Antes de um ativo ser liberado, o Java Runtime chama o método finalize () no objeto. O método finalize () tem a seguinte forma geral:
Com a palavra-chave protegida , o acesso a finalize () por código fora de sua classe é impedido. É importante entender que finalize () é chamado logo antes da coleta de lixo. Não é chamado quando um objeto sai do escopo, por exemplo. Isso significa que você não pode saber quando ou se finalize () será executado. Como resultado, o programa deve fornecer outros meios para liberar recursos do sistema ou outros recursos usados pelo objeto. Você não deve confiar em finalize () para a execução normal do programa.
fonte
Classe em que substituímos o método finalize
As chances de finalizar o método sendo chamado
quando a memória está sobrecarregada com objetos de despejo, o gc chama o método finalize
execute e veja o console, onde você não encontra o método finalize sendo chamado com freqüência, quando a memória está ficando sobrecarregada, o método finalize será chamado.
fonte
Fonte
fonte
finalize()
é chamado logo antes da coleta de lixo. Não é chamado quando um objeto sai do escopo. Isso significa que você não pode saber quando ou mesmo sefinalize()
será executado.Exemplo:
Se o seu programa terminar antes que o coletor de lixo ocorra, ele
finalize()
não será executado. Portanto, ele deve ser usado como procedimento de backup para garantir o manuseio adequado de outros recursos ou para aplicativos de uso especial, não como o meio que seu programa usa em sua operação normal.fonte
Conforme indicado em https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ,
fonte
Tente executar este programa para entender melhor
fonte