Quando o método finalize () é chamado em Java?

330

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?

Rajesh Kumar J
fonte
34
Apenas como uma observação lateral: finalize está marcado como obsoleto no Java 9
Reg
se alguma coisa tem uma referência ao seu objeto ou mesmo à classe. finalize()e coleta de lixo não tem nenhum impacto.
precisa saber é o seguinte

Respostas:

273

Em geral, é melhor não confiar finalize()para fazer qualquer limpeza, etc.

De acordo com o Javadoc (que valeria a pena ler), é:

Chamado pelo coletor de lixo em um objeto quando a coleta de lixo determina que não há mais referências ao objeto.

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.

Paul Bellora
fonte
19
Em outras palavras (apenas para esclarecer aos futuros leitores), nunca é chamado à classe principal, pois, quando a classe principal é fechada, nenhum lixo precisa ser coletado. O sistema operacional limpa tudo o que o aplicativo usou de qualquer maneira.
Mark Jeronimus
113
"não é o melhor método para usar ... a menos que haja algo específico para o qual você precise" - essa frase se aplica a 100% de tudo, por isso não é útil. A resposta de Joachim Sauer é muito melhor
BT
1
@ Zom-B, seu exemplo é útil para esclarecimentos, mas apenas para ser pedante, presumivelmente poderia ser chamado na classe principal se a classe principal criar um encadeamento que não seja daemon e depois retornar?
Tom G
3
Então, quais são as situações em finalizeque seriam úteis?
Nbro
3
@ MarkJeronimus - Na verdade, isso é irrelevante. O 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 ....)
Stephen C
379

O finalizemé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, finalizenunca é 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 finalizeem 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 finalizeoperação correta do seu aplicativo, estará fazendo algo errado. finalizedeve ser usado apenas para limpeza de recursos (geralmente não Java). E isso é exatamente porque a JVM não garante que finalizealguma vez seja chamada em qualquer objeto.

Joachim Sauer
fonte
2
@Rajesh. Não. Não é uma questão de "duração da vida". Você pode colocar seu programa em um loop infinito (por anos) e, se o coletor de lixo não for necessário, ele nunca será executado.
ChrisCantrell
5
@ VikasVerma: o substituto perfeito não é nada: você não precisa deles. O único caso em que faria sentido é se sua classe gerencia algum recurso externo (como uma conexão TCP / IP, arquivo ... qualquer coisa que o Java GC não possa manipular). Nesses casos, a Closableinterface (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 um finalizemé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).
Joachim Sauer
4
@ Dragonborn: essa é realmente uma pergunta bem diferente e deve ser feita separadamente. Existem ganchos de encerramento, mas eles não são garantidos se a JVM for desligada inesperadamente (também conhecida como travamento). Mas suas garantias são significativamente mais fortes do que as dos finalizadores (e também são mais seguras).
Joachim Sauer
4
Seu último parágrafo diz para usá-lo apenas para limpar recursos, mesmo que não haja garantia de que algum dia será chamado. Esse otimismo está falando? Eu assumiria que algo não confiável, pois isso também não seria adequado para limpar recursos.
Jeroen Vannevel 18/04/2015
2
Às vezes, os finalizadores podem salvar o dia ... Eu tive um caso em que uma biblioteca de terceiros usava um FileInputStream, nunca o fechava. Meu código estava chamando o código da biblioteca e tentei mover o arquivo, falhando porque ainda estava aberto. Eu tive que forçar a chamada System.gc()para chamar FileInputStream :: finalize (), para poder mover o arquivo.
Elist 8/08/18
73
protected void finalize() throws Throwable {}
  • toda classe herda o finalize()método de java.lang.Object
  • o método é chamado pelo coletor de lixo quando determina que não existem mais referências ao objeto
  • o método Object finalize não executa nenhuma ação, mas pode ser substituído por qualquer classe
  • normalmente deve ser substituído para limpar recursos não Java, ou seja, fechar um arquivo
  • se substituir finalize(), é uma boa prática de programação usar uma instrução try-catch-finalmente e sempre chamar super.finalize(). Essa é uma medida de segurança para garantir que você não perca inadvertidamente o fechamento de um recurso usado pelos objetos que chamam a classe

    protected void finalize() throws Throwable {
         try {
             close();        // close open files
         } finally {
             super.finalize();
         }
     }
  • qualquer exceção lançada finalize()durante a coleta de lixo interrompe a finalização, mas é ignorada

  • finalize() nunca é executado mais de uma vez em qualquer objeto

citado em: http://www.janeg.ca/scjp/gc/finalize.html

Você também pode verificar este artigo:

XpiritO
fonte
25
O artigo do JavaWorld ao qual você vincula é de 1998 e tem alguns conselhos interessantes, particularmente a sugestão de que se chame System.runFinalizersOnExit () para garantir que os finalizadores sejam executados antes da saída da JVM. Esse método está atualmente obsoleto, com o comentário 'Este método é inerentemente inseguro. Isso pode resultar em finalizadores sendo chamados em objetos ativos, enquanto outros threads estão manipulando simultaneamente esses objetos, resultando em comportamento irregular ou conflito. ' Então eu não vou fazer isso.
precisa
3
Como runFinalizerOnExit () NÃO é seguro para threads, o que se pode fazer é Runtime.getRuntime (). AddShutdownHook (new Thread () {public void run () {destroyMyEnclosingClass ();}}); no construtor da classe.
Ustaman Sangat
2
@ Ustaman Sangat Essa é uma maneira de fazer isso, mas lembre-se de que isso define uma referência à sua instância no shutdownHook, o que praticamente garante que sua classe nunca seja coletada como lixo. Em outras palavras, é um vazamento de memória.
pieroxy
1
@ pieroxy, embora eu concorde com todos os outros aqui a respeito de não usar finalize () para nada, não vejo por que haveria uma referência no gancho de desligamento. Pode-se ter uma referência suave.
perfil completo de Ustaman Sangat
25

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 o finalizemétodo seja chamado durante o tempo de vida do aplicativo.

O que você provavelmente quer é uma combinação finallye um método de limpeza, como em:

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

    if (null != myObj) {
        myObj.cleanup();
    }
}
rsp
fonte
20

Confira o Effective Java, segunda edição, página 27. Item 7: Evite finalizadores

Os finalizadores são imprevisíveis, geralmente perigosos e geralmente desnecessários. nunca faça nada crítico em um finalizador. nunca dependa de um finalizador para atualizar o estado persistente crítico.

Para finalizar um recurso, use try-finalmente:

// try-finally block guarantees execution of termination method
Foo foo = new Foo(...);
try {
    // Do what must be done with foo
    ...
} finally {
    foo.terminate(); // Explicit termination method
}
Hao Deng
fonte
3
ou use try-with-resources
Gabriel Garcia
3
Isso pressupõe que a vida útil de um objeto esteja no escopo de uma função. O que, é claro, não é o caso ao qual o OP está se referindo, nem é basicamente o que alguém precisa. Pense em "contagem de referência do valor de retorno do mecanismo de cache". Você deseja liberar a entrada do cache quando a última ref é liberada, mas não sabe quando a última ref é liberada. finalize () pode diminuir uma contagem de referências, por exemplo ... mas se você exigir que seus usuários chamem explicitamente uma função livre, você está solicitando vazamentos de memória. Normalmente eu só fazer as duas coisas (a liberação de função + double check in finalize ...) ...
Erik Aronesty
16

Quando o finalize()método é chamado em Java?

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 ...)


Criei uma classe de teste que grava em um arquivo quando o método finalize () é chamado, substituindo-o. Não é executado. Alguém pode me dizer o motivo pelo qual não está sendo executado?

É difícil dizer, mas existem algumas possibilidades:

  • O objeto não é coletado como lixo porque ainda é acessível.
  • O objeto não é coletado como lixo porque o GC não é executado antes da conclusão do teste.
  • O objeto é encontrado pelo GC e colocado na fila de finalização pelo GC, mas a finalização não é concluída antes do término do teste.
Stephen C
fonte
10

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 nullobjeto cque obviamente não tem uso futuro; portanto, vemos a cchamada finalizada do objeto .

Exemplo

class Car {

    int maxspeed;

    Car() {
        maxspeed = 70;
    }

    protected void finalize() {

    // Originally finalize method does nothing, but here we override finalize() saying it to print some stmt
    // Calling of finalize is uncertain. Difficult to observe so we force JVM to call it by System.gc(); GarbageCollection

        System.out.println("Called finalize method in class Car...");
    }
}

class Bike {

    int maxspeed;

    Bike() {
        maxspeed = 50;
    }

    protected void finalize() {
        System.out.println("Called finalize method in class Bike...");
    }
}

class Example {

    public static void main(String args[]) {
        Car c = new Car();
        c = null;    // if c weren`t null JVM wouldn't be certain it's cleared or not, null means has no future use or no longer in use hence clears it
        Bike b = new Bike();
        System.gc();    // should clear c, but not b
        for (b.maxspeed = 1; b.maxspeed <= 70; b.maxspeed++) {
            System.out.print("\t" + b.maxspeed);
            if (b.maxspeed > 50) {
                System.out.println("Over Speed. Pls slow down.");
            }
        }
    }
}

Resultado

    Called finalize method in class Car...
            1       2       3       4       5       6       7       8       9
    10      11      12      13      14      15      16      17      18      19
    20      21      22      23      24      25      26      27      28      29
    30      31      32      33      34      35      36      37      38      39
    40      41      42      43      44      45      46      47      48      49
    50      51Over Speed. Pls slow down.
            52Over Speed. Pls slow down.
            53Over Speed. Pls slow down.
            54Over Speed. Pls slow down.
            55Over Speed. Pls slow down.
            56Over Speed. Pls slow down.
            57Over Speed. Pls slow down.
            58Over Speed. Pls slow down. 
            59Over Speed. Pls slow down.
            60Over Speed. Pls slow down.
            61Over Speed. Pls slow down.
            62Over Speed. Pls slow down.
            63Over Speed. Pls slow down.
            64Over Speed. Pls slow down.
            65Over Speed. Pls slow down.
            66Over Speed. Pls slow down.
            67Over Speed. Pls slow down.
            68Over Speed. Pls slow down.
            69Over Speed. Pls slow down.
            70Over Speed. Pls slow down.

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.

techloris_109
fonte
10
Ligar System.gc();não é uma garantia de que a coleta de lixo será realmente executada.
Simon Forsberg
3
Também não é garantido que tipo de coleção será executada. Relevante, pois a maioria dos Java GCs são coletores "geracionais".
Stephen C
5

finalize imprimirá a contagem para a criação da classe.

protected void finalize() throws Throwable {
    System.out.println("Run F" );
    if ( checkedOut)
        System.out.println("Error: Checked out");
        System.out.println("Class Create Count: " + classCreate);
}

a Principal

while ( true) {
    Book novel=new Book(true);
    //System.out.println(novel.checkedOut);
    //Runtime.getRuntime().runFinalization();
    novel.checkIn();
    new Book(true);
    //System.runFinalization();
    System.gc();

Como você pode ver. O exemplo a seguir mostra que o gc foi executado pela primeira vez quando a contagem de turmas é 36.

C:\javaCode\firstClass>java TerminationCondition
Run F
Error: Checked out
Class Create Count: 36
Run F
Error: Checked out
Class Create Count: 48
Run F
user1623624
fonte
4

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):

  • Finalizar não é chamado imediatamente, o Finalizador (parte do GC) possui a referência de forma indescritível
  • O Garbage Collector padrão agrupa objetos inacessíveis
  • Finalize é chamado em massa, apontando para um detalhe de implementação que indica que há uma certa fase em que o coletor de lixo libera os recursos.
  • Chamar System.gc () geralmente não resulta na finalização dos objetos com mais frequência, apenas no Finalizer, tornando mais rápido o reconhecimento de um objeto inacessível
  • A criação de um dump de encadeamento quase sempre resulta no acionamento do finalizador devido à alta sobrecarga de heap durante a execução do dump de heap ou algum outro mecanismo interno
  • As costuras de finalização devem ser vinculadas por requisitos de memória (libere mais memória) ou pela lista de objetos marcados para finalização crescente de um determinado limite interno. Portanto, se você tiver muitos objetos finalizados, a fase de finalização será acionada com mais frequência e mais cedo quando comparada com apenas alguns
  • Houve circunstâncias em que System.gc () acionou uma finalização diretamente, mas apenas se a referência fosse de vida local e curta. Isso pode estar relacionado à geração.

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.

Martin Kersten
fonte
2

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:

  1. Todas as referências desse objeto são explicitamente definidas como nulas, por exemplo, object = null
  2. O objeto é criado dentro de um bloco e a referência sai do escopo quando o controle sai desse bloco.
  3. Objeto pai definido como nulo, se um objeto mantiver a referência de outro objeto e quando você definir a referência do objeto de contêiner nulo, o objeto filho ou contido se tornará automaticamente elegível para coleta de lixo.
  4. Se um objeto tiver apenas referências ativas via WeakHashMap, será elegível para coleta de lixo.
Tushar Trivedi
fonte
Se um finalcampo 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?
Supercat
@ supercat: um otimizador pode reescrever o código em um formulário em que o objeto não seja criado; nesse caso, ele pode ser finalizado logo após a conclusão do construtor, a menos que a sincronização force uma ordem entre o uso do objeto e o finalizador.
Holger
@ Holger: Nos casos em que o JIT pode ver tudo o que acontecerá com um objeto entre sua criação e abandono, não vejo nenhuma razão para o JIT disparar o finalizador mais cedo. A verdadeira questão seria o que o código precisa fazer para garantir que o finalizador não possa ser acionado dentro de um método específico. No .NET, existe uma 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 usar volatilevariável para esse fim, mas o uso de uma variável exclusivamente para esse objetivo pareceria um desperdício.
Supercat
@supercat: O JIT não aciona a finalização, apenas organiza o código para não manter uma referência; no entanto, pode ser benéfico enfileirar diretamente o 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 adicionar Reference.reachabilityFence
Holger
@ Holger: Se o JIT otimizar a criação de objetos, o único Finalizeseria 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 ... #
308
2

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.

giri
fonte
3
Incorreta. O que você está dizendo é que um objeto é finalizado quando se torna inacessível. Na verdade, é chamado quando o método é realmente coletado.
Stephen C
2

À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:

protected void finalize(){
    // This is where the finalization code is entered
}

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.

Amarildo
fonte
1

Classe em que substituímos o método finalize

public class TestClass {    
    public TestClass() {
        System.out.println("constructor");
    }

    public void display() {
        System.out.println("display");
    }
    @Override
    public void finalize() {
        System.out.println("destructor");
    }
}

As chances de finalizar o método sendo chamado

public class TestGarbageCollection {
    public static void main(String[] args) {
        while (true) {
            TestClass s = new TestClass();
            s.display();
            System.gc();
        }
    }
}

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.

pradeep
fonte
0

Java permite que objetos implementem um método chamado finalize () que pode ser chamado.

O método finalize () é chamado se o coletor de lixo tentar coletar o objeto.

Se o coletor de lixo não for executado, o método não será chamado.

Se o coletor de lixo falhar na coleta do objeto e tentar executá- lo novamente, o método não será chamado na segunda vez.

Na prática, é improvável que você o use em projetos reais.

Lembre-se de que talvez não seja chamado e que definitivamente não será chamado duas vezes. O método finalize () pode executar zero ou uma vez.

No código a seguir, o método finalize () não produz saída quando o executamos, pois o programa é encerrado antes que seja necessário executar o coletor de lixo.

Fonte

JavaDev
fonte
0

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 se finalize()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.

AyukNayr
fonte
0

Conforme indicado em https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ,

Não há tempo fixo no qual os finalizadores devem ser executados porque o tempo de execução depende da Java Virtual Machine (JVM). A única garantia é que qualquer método finalizador que seja executado o faça algum tempo após o objeto associado se tornar inacessível (detectado durante o primeiro ciclo de coleta de lixo) e algum tempo antes do coletor de lixo recuperar o armazenamento do objeto associado (durante o segundo ciclo do coletor de lixo) . A execução do finalizador de um objeto pode ser atrasada por um tempo arbitrariamente longo após o objeto ficar inacessível. Conseqüentemente, a invocação de funcionalidades críticas como o fechamento de identificadores de arquivo no método finalize () de um objeto é problemática.

Utkarsh Gupta
fonte
-3

Tente executar este programa para entender melhor

public class FinalizeTest 
{       
    static {
        System.out.println(Runtime.getRuntime().freeMemory());
    }

    public void run() {
        System.out.println("run");
        System.out.println(Runtime.getRuntime().freeMemory());
    }

     protected void finalize() throws Throwable { 
         System.out.println("finalize");
         while(true)
             break;          
     }

     public static void main(String[] args) {
            for (int i = 0 ; i < 500000 ; i++ ) {
                    new FinalizeTest().run();
            }
     }
}
user3836455
fonte