Por que o método finalize está incluído em Java?

44

De acordo com esta postagem , nunca devemos confiar no método finalize a ser chamado. Então, por que o Java incluiu isso na linguagem de programação?

Parece uma decisão terrível incluir em qualquer linguagem de programação uma função que possa ser chamada.

    
por patstuart 25.06.2014 / 19:07
fonte

7 respostas

41

De acordo com o Effective Java de Joshua Bloch (Segunda Edição), existem dois cenários em que finalize() é útil:

  1. One is to act as a “safety net” in case the owner of an object forgets to call its explicit termination method. While there’s no guarantee that the finalizer will be invoked promptly, it may be better to free the resource late than never, in those (hopefully rare) cases when the client fails to call the explicit termination method. But the finalizer should log a warning if it finds that the resource has not been terminated

  2. A second legitimate use of finalizers concerns objects with native peers. A native peer is a native object to which a normal object delegates via native methods. Because a native peer is not a normal object, the garbage collector doesn’t know about it and can’t reclaim it when its Java peer is reclaimed. A finalizer is an appropriate vehicle for performing this task, assuming the native peer holds no critical resources. If the native peer holds resources that must be terminated promptly, the class should have an explicit termination method, as described above. The termination method should do whatever is required to free the critical resource.

Para mais informações, consulte o item 7, página 27.

    
por 25.06.2014 / 22:38
fonte
55

Finalizadores são importantes para o gerenciamento de recursos nativos. Por exemplo, seu objeto pode precisar alocar um WidgetHandle do sistema operacional usando uma API não Java. Se você não liberar esse WidgetHandle quando seu objeto for GC, você estará vazando WidgetHandles.

O que é importante é que os casos de "finalizador nunca é chamado" são simplesmente:

  1. O programa é encerrado rapidamente
  2. O objeto "vive para sempre" durante o tempo de vida do programa
  3. O computador é desligado / seu processo é eliminado pelo SO / etc

Em todos esses três casos, você não tem um vazamento nativo (em virtude do fato de seu programa não estar mais sendo executado), ou você já tem um -native vazamento (se você continuar alocando objetos gerenciados sem que eles tenham GC'd).

O aviso "não confie no finalizador sendo chamado" é realmente sobre não usar finalizadores para a lógica do programa. Por exemplo, você não quer acompanhar quantos de seus objetos existem em todas as instâncias de seu programa, incrementando um contador em um arquivo em algum lugar durante a construção e diminuindo-o em um finalizador - porque não há garantia de que seus objetos seja finalizado, este contador de arquivos provavelmente nunca voltará para 0. Este é realmente um caso especial do princípio mais geral de que você não deve depender de seu programa terminar normalmente (falhas de energia, etc).

Para o gerenciamento de recursos nativos, porém, os casos em que o finalizador não é executado correspondem aos casos em que você não se importa se ele não é executado.

    
por 25.06.2014 / 20:26
fonte
5

A finalidade deste método é explicada na documentação da API da seguinte forma:

it is invoked if and when the Java virtual machine has determined that there is no longer any means by which this object can be accessed by any thread that has not yet died, except as a result of an action taken by the finalization of some other object or class which is ready to be finalized...

the usual purpose of finalize... is to perform cleanup actions before the object is irrevocably discarded. For example, the finalize method for an object that represents an input/output connection might perform explicit I/O transactions to break the connection before the object is permanently discarded...

Se você também estiver interessado em motivos pelos quais os designers de linguagem escolheram esse "objeto irrevogavelmente descartado" ( coleta de lixo ) do modo que está além do controle do programador de aplicativos ("nunca devemos confiar"), isso foi explicado em uma resposta à questão relacionada :

automatic garbage collection... eliminates entire classes of programming errors that bedevil C and C++ programmers. You can develop Java code with confidence that the system will find many errors quickly and that major problems won't lay dormant until after your production code has shipped..

A citação acima, por sua vez, foi retirada da documentação oficial sobre as metas de design de Java , que pode ser considerado referência autoritária explicando por que os projetistas de linguagem Java decidiram dessa maneira.

Para uma discussão agnóstica mais detalhada e linguística desta preferência, consulte OOSC seção 9.6 Gerenciamento automático de memória (na verdade, não apenas esta seção, mas todo o capítulo 9 vale a pena ser lido se você estiver interessado em coisas assim). Esta seção abre com uma declaração inequívoca:

A good O-O environment should offer an automatic memory management mechanism which will detect and reclaim unreachable objects, allowing application developers to concentrate on their job — application development.

The preceding discussion should suffice to show how important it is to have such a facility available. In the words of Michael Schweitzer and Lambert Strether:

An object-oriented program without automatic memory management is roughly the same as a pressure cooker without a safety valve: sooner or later the thing is sure to blow up!

    
por 25.06.2014 / 19:18
fonte
4

Os finalizadores existem porque se espera que sejam um meio efetivo de garantir que as coisas sejam limpas (mesmo que na prática não sejam) e porque, quando foram inventadas, melhores meios de garantir a limpeza (como referências fantasmas e try-with-resources) ainda não existiam. Em retrospectiva, o Java provavelmente seria melhor se o esforço gasto na implementação de sua instalação "finalizada" tivesse sido gasto em outros meios de limpeza, mas isso não estava claro durante o tempo em que o Java estava sendo desenvolvido inicialmente.

    
por 02.07.2014 / 18:26
fonte
3

CAVEAT: Eu posso estar desatualizado, mas este é o meu entendimento há alguns anos atrás:

Em geral, não há garantia de quando um finalizador é executado - ou mesmo que ele seja executado, embora algumas JVMs permitam que você solicite um GC completo e finalização antes da saída do programa (o que, é claro, significa que o programa demora mais para sair, e que não é o modo padrão de operação).

E alguns GCs eram conhecidos por atrasar explicitamente ou evitar objetos GC'ing que tinham finalizadores, na esperança de que isso produziria melhor desempenho em benchmarks.

Esses comportamentos infelizmente conflitam com as razões originais recomendadas pelos finalizadores e incentivaram o uso de métodos explicitamente chamados de desligamento.

Se você tem um objeto que realmente precisa ser limpo antes de ser descartado, e se você realmente não pode confiar nos usuários, um finalizador ainda pode valer a pena considerar. Mas, em geral, existem Boas Razões em que você não as vê com tanta frequência em códigos Java modernos quanto em alguns dos primeiros exemplos.

    
por 26.06.2014 / 01:47
fonte
1

O Guia de Estilo Java do Google tem alguns conselhos sábios sobre o assunto:

It is extremely rare to override Object.finalize.

Tip: Don't do it. If you absolutely must, first read and understand Effective Java Item 7, "Avoid Finalizers," very carefully, and then don't do it.

    
por 26.06.2014 / 06:36
fonte
1

A Especificação da linguagem Java (Java SE 7) estados:

Finalizers provide a chance to free up resources that cannot be freed automatically by an automatic storage manager. In such situations, simply reclaiming the memory used by an object would not guarantee that the resources it held would be reclaimed.

    
por 02.07.2014 / 15:17
fonte