44

According to this post, we should never rely on the finalize method to be called. So why did Java include it in the programming language at all?

It seems like a terrible decision to include in any programming language a function that might get called.

0

7 Answers 7

41

According to Joshua Bloch's Effective Java (Second Edition), there are two scenarios when finalize() is useful:

  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.

For further reading, refer to Item 7, page 27.

2
  • 4
    With #2 sounds like the native peer is a native resource that requires a safety net and should have a termination method, and thus shouldn't be a separate point. Commented Jun 26, 2014 at 0:05
  • 2
    @MooingDuck: #2 is a separate point because, if the native peer does not hold critical resources (e.g. it is purely an in-memory object), then there is no need to expose an explicit termination method. The safety net from #1 is explicitly about having a termination method.
    – jhominal
    Commented Jun 26, 2014 at 5:09
56

Finalizers are important for the management of native resources. For example, your object might need to allocate a WidgetHandle from the operating system using a non-Java API. If you don't release that WidgetHandle when your object is GC'd, you're going to be leaking WidgetHandles.

What's important is that the "finalizer is never called" cases break down rather simply:

  1. The program shuts down quickly
  2. The object "lives forever" during the lifetime of the program
  3. The computer turns off / your process is killed by the OS / etc

In all three of these cases, you either don't have a native leak (by virtue of the fact that your program is not running anymore), or you already have a non-native leak (if you keep allocating managed objects without them being GC'd).

The "don't rely on the finalizer being called" warning is really about not using finalizers for program logic. For example, you don't want to keep track of how many of your objects exist across all instances of your program by incrementing a counter in a file somewhere during construction and decrementing it in a finalizer -- because there's no guarantee that your objects will be finalized, this file counter will probably not ever go back to 0. This is really a special case of the more general principle that you shouldn't depend on your program terminating normally (power failures, etc).

For management of native resources, though, the cases where the finalizer doesn't run correspond to cases where you don't care if it doesn't run.

7
  • Excellent answer. I was like even if it might be called.. it should still be included. I was confused for a while with the question and the linked one on StackOverflow.
    – InformedA
    Commented Jun 25, 2014 at 18:35
  • 3
    It wasn't in the question, but it's worth discussing in the context of "don't rely on the finalizer being called": The finalizer may be called, but only after an arbitrarily long delay after the object becomes unreachable. This matters for "native resources" which are far more scarce than memory (which are most of them, it turns out).
    – user7043
    Commented Jun 25, 2014 at 18:50
  • 26
    "Finalizers are important for the management of native resources." - nooooooooo, ahem sorry. Using finalizers for managing native resources is a horrible idea (which is why we have autocloseable and co now). The GC only cares about memory, not any other resource. This means you can run out of native resources but still have enough memory to not trigger a GC - we really don't want that. Also finalizers make GC more expensive which isn't a good idea either.
    – Voo
    Commented Jun 25, 2014 at 21:42
  • 12
    I agree you should still have an explicit native resource management strategy other than finalizers, but if your object does allocate them and doesn't free them in the finalizer, you're opening yourself up to a native leak in the case where the object is GC'd without the explicit freeing of the resource. In other words, finalizers are an important part of a native resource management strategy, not a solution to the problem in general. Commented Jun 25, 2014 at 22:21
  • 1
    @Voo it's probably more correct to say the finalizer is the fallback in case the contract of the object is not followed (close() is never called before it becomes unreachable) Commented Jun 26, 2014 at 10:34
5

Purpose of this method is explained in API documentation as follows:

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


If you're additionally interested in reasons why language designers have chosen that "object is irrevocably discarded" (garbage collected) the way that is beyond application programmer control ("we should never rely"), this has been explained in an answer to related question:

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

Above quote, in turn, was taken from official documentation about Java design goals, that is it can be considered authoritative reference explaining why Java language designers decided this way.

For a more detailed and language agnostic discussion of this preference, refer OOSC section 9.6 Automatic memory management (actually, not only this section but the whole chapter 9 is very worth reading if you're interested in stuff like that). This section opens with an unambiguous statement:

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!

4

Finalizers exist because they were expected to be an effective means of ensuring that things get cleaned up (even though in practice they aren't), and because when they were invented, better means of ensuring cleanup (such as phantom references and try-with-resources) didn't exist yet. In hindsight, Java would likely be better if the effort spent on implementing its "finalize" facility had been spent on other means of cleanup, but that was hardly clear during the time Java was initially being developed.

3

CAVEAT: I may be out of date, but this is my understanding as of a few years ago:

In general, there is no guarantee of when a finalizer runs -- or even that it runs at all, though some JVMs will let you request a complete GC and finalization before the program exits (which, of course, means that the program takes longer to exit, and which isn't the default mode of operation).

And some GCs were known to explicitly delay or avoid GC'ing objects that had finalizers, in the hope that this would produce better performance on benchmarks.

These behaviors unfortunately conflict with the original reasons finalizers were recommended, and have encouraged the use of explicitly-called shutdown methods instead.

If you have an object that really has to be cleaned up before being discarded, and if you really can't trust the users to do so, a finalizer may still be worth considering. But in general, there are Good Reasons that you don't see them as often in modern Java code as you did in some of the early examples.

1

The Google Java Style Guide has some sage advice on the subject:

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.

9
  • 5
    Why I admire the oversimplification of the problem, "don't do it" is not an answer to "why does it exist". Commented Jun 26, 2014 at 8:41
  • 1
    I guess I didn't spell it out well in my answer, but (IMO) the answer to "why does it exist?" is "it shouldn't". For those rare cases where you really need a finalization operation, you probably want to build it yourself with PhantomReference and ReferenceQueue instead. Commented Jun 26, 2014 at 14:54
  • I meant while* obviously, though I didn't downvote you. The most upvoted answer does however show how useful the method is, kinda invalidating your point. Commented Jun 26, 2014 at 14:57
  • 1
    Even in the native peer case, I think PhantomReference is a better solution. Finalizers are a wart left over from the early days of Java, and like Object.clone() and raw types, are a part of the language best forgotten. Commented Jun 26, 2014 at 15:05
  • 1
    The dangers of finalizers are described in a more accessible (understandable by developers) manner in C#., Though, one must not imply that the underlying mechanisms on Java and C# are same; there's nothing in their specifications that say so.
    – rwong
    Commented Jul 2, 2014 at 19:12
1

The Java Language Specification (Java SE 7) states:

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.