The true purpose of finalize()

M

Matt

So what is finalize() for exactly? Why would the garbage ever need
help? Could someone give me an example of a good use for finalize()?

Thanks!
Matt
 
R

RedGrittyBrick

Matt said:
So what is finalize() for exactly? Why would the garbage ever need
help? Could someone give me an example of a good use for finalize()?

For releasing resources other than memory. The garbage collector only
collects memory. E.g. closing files, terminating network connections.

I've never needed to use finalize. I release resources using this pattern:

<obtain resource>
try {
<use resource>
} finally {
<release resource>
}

The other examples I've seen mentioned are when you use JNI to allocate
resources.
 
L

Lew

RedGrittyBrick said:
For releasing resources other than memory. The garbage collector only
collects memory. E.g. closing files, terminating network connections.

Not actually correct. Depending on 'finalize()' to release resources
is a recipe to fail to release resources. It is used for that only as
a court of last resort in case some client code fails to release
resources, and even then is usually a bad idea.
I've never needed to use finalize.

No one ever needs to use finalize() to release resources.

'finalize()', according to Joshua Bloch in his seminal /Effective
Java/, has two legitimate uses. One is as the aforementioned last
resort for when resources are not properly released, and not a very
good one there. The other is to coordinate with JNI code to release
memory on the native side when the Java object is reclaimed, if ever.
Read /Effective Java/ for why finalizers are otherwise a terrible
choice, and how to make them work properly in the rare cases when you
do need them.
I release resources using this pattern:
   <obtain resource>
   try {
     <use resource>
   } finally {
     <release resource>
   }

The other examples I've seen mentioned are when you use JNI to allocate
resources.

Well, Mr. Bloch points out that a "finalizer is an appropriate vehicle
for performing this task [releasing a native peer], /assuming the
native peer holds no critical resources/." (Emphasis original) In
other words, finalizers are not about releasing resources generally,
only memory.

Even when finalizers are appropriate, you have to be very, very
careful. A badly-written finalizer can hold huge object trees in
memory, potentially never to be reclaimed. You have to deliberately
limit the reach of a finalizer-laden class to avoid that flaw.
 
M

Mark Space

Eric said:
Bruce Eckel suggests using finalize() not to perform the close()
or dispose() or whatever, but to help debug a failure to call it:

class Thing {
...
private boolean alive = true;
void dispose() { alive = false; ... }
public void finalize() throws Throwable {
if (alive)
complainLoudlyAboutFailureToDispose();
super.finalize();
}
}

I'm not entirely convinced this is worth while -- but I'm also not
convinced it's useless.

That's interesting. I wonder if the compiler would recognize an empty
finalizer as "trivial" and not actually invoke (or mark) it.

public void finalize() throws FinalException {
if( DEBUG ) // DEBUG = false for production code
{
if( alive )
throw new FinalException();
}
super.finalize();
}

This might be more practical....
 
L

Lew

Mark said:
I wonder if the compiler would recognize an empty
finalizer as "trivial" and not actually invoke (or mark) it.

The JLS says:
For efficiency, an implementation may keep track of classes that
do not override the finalize method of class Object,
or override it in a trivial way, such as:

protected void finalize() throws Throwable {
super.finalize();
}

We encourage implementations to treat such objects as having a finalizer
that is not overridden, and to finalize them more efficiently, as
described in §12.6.1.

This hints that some JVMs might do that, but not to count on it.

The presence of an if ( false ) as you suggest is less likely to be
seen as trivial.
 
M

Mike Schilling

Lew said:
Well, Mr. Bloch points out that a "finalizer is an appropriate vehicle
for performing this task [releasing a native peer], /assuming the
native peer holds no critical resources/." (Emphasis original) In
other words, finalizers are not about releasing resources generally,
only memory.

Even when finalizers are appropriate, you have to be very, very
careful. A badly-written finalizer can hold huge object trees in
memory, potentially never to be reclaimed. You have to deliberately
limit the reach of a finalizer-laden class to avoid that flaw.

Note also that finalize() goes back to Java 1.0, before weak references and
reference queues were added to the platform. For most kinds of cleanup,
they're a much better solution; in fsct I can't offhand think of a use of
finalize() that doesn't work at least as well with reference queues. E.g.,
place the information about the native peer in the WeakReference
(subclassing WeakReference to allow this) and delete the native memory when
the WeakReference is delivered.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top