9

I had the general view that clean up of resources is done in the finally block,
recently I found this particular code snippet in a class and it was overriding the Object class' finalize() method.

protected void finalize() {  
    try {
        In.close(); 
        Out.close();
        socket.close();
    }
    catch (Exception e) {
        //logger code here
    }
}

Is this a good idea? What are the pros and cons of finalize() over finally?

Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
Kevin Boyd
  • 12,121
  • 28
  • 86
  • 128
  • finalized() should never have been used. if a developer forgot to close(), don't help him. let the resource leak, so the problem can be noticed and fixed. Java 7 will introduce better ways of resource closing, so there will be finally no excuse for finalized() any more. – irreputable Dec 04 '09 at 02:35
  • IIRC, a single thread is dedicated to running finalize() on various objects. It is one way to bring a system to its knees in terms of performance. – Michael Easter Dec 04 '09 at 03:44

9 Answers9

16

The finally block is just a block of code that always executes after a try block, even if there is an exception. i.e. it is local in scope

The finalize() method is an approach for cleaning up the whole object when it is garbage collected.

Java documentation of finalize()

finally solves the problem of cleaning up resources in a block of code regardless of whether an exceptional condition occurs... finalize() is a way to clean up resources when your object is no longer being used, once the Garbage Collecter determines there are no more references to that object.

In short, to answer your question, for example, if the sockets you are closing are members of an object you should close them in the finalize() method, (although that's sub-optimal, and just for example, because there is no guarantee when the GC will actually perform the action)

If however you're opening the socket in a method, and are done with it when the method ends you should free the resources in the finally block.

Voqus
  • 159
  • 1
  • 11
John Weldon
  • 39,849
  • 11
  • 94
  • 127
  • 5
    Nice - a Java question with a C# article to answer it. Beware that the details in the article may or may not be relevant to Java. – Lawrence Dol Dec 03 '09 at 23:56
  • I've updated the link for the Java implementation. Sorry for the confusion. – John Weldon Dec 04 '09 at 01:06
  • @JohnWeldon - This sentence seems to imply that 'finally' block is only executed in case of an exception, which is false: "finally only solves the problem of cleaning up resources in an exceptional condition". – Andy Thomas Dec 30 '11 at 17:38
8

Always clean up things in finally.

Cleaning up in finalize is not guaranteed to occur.

However, it is often found to clean up such things in finalizers as a last-ditch safety valve should a finally block throw another exception on you.

The real problem with relying on finalizers is something else may need the resource before the GC gets around to calling the finalizer.

Joshua
  • 40,822
  • 8
  • 72
  • 132
  • 1
    They are not alternatives to one another. – Adam Robinson Dec 03 '09 at 23:53
  • finally are not always possible--they will only work if your code flows continuously from where your resource is allocated to where it's cleaned up. What if you allocate it when opening a GUI screen and clean it up after the user hits the "OK" button? – Bill K Dec 04 '09 at 00:25
  • FYI: `finalize` will always be called when the garbage collector gets around to it. However, the key is "when the garbage collector gets around to it." A fully-conforming implementation of Java might not get around to calling `finalize` before the heat death of the universe. – Chip Uni Dec 04 '09 at 01:08
  • @Chip - The JLS says this: "The Java programming language does not specify how soon a finalizer will be invoked, except to say that it will happen before the storage for the object is reused.". So it is legal for the GC to detect that a finalizer needs to be run, but simply never run it ... provided that it doesn't actually reuse the object's memory. – Stephen C Dec 04 '09 at 01:21
5

Phantom References will do what you want.

Just don't use finalize. There are a few edge cases where it may be helpful (printing debug info when a class is GC'd has come in handy), but in general don't. There is nothing in the JVM contract that even says it ever has to be called.

There is a very under-publicized type of object called "References". One is made explicitly for things that you think you would use finalize for.

"Phantom reference objects, which are enqueued after the collector determines that their referents may otherwise be reclaimed."

It just occurred to me that there MUST be a description of this on the web--so I'll replace all the "how-to" stuff I just wrote with this reference.

Bill K
  • 62,186
  • 18
  • 105
  • 157
  • I didn't know that since finalize predated references--they must have reimplemented it (For instance, the system I'm working on does not have references but it still has finalize). The point was, you can't rely on finalize across implementations to be called. It might work, there might be a command-line switch that forces it to be called before exit, but it's runtime dependent, not something you can control at compile time. Phantom References have a reliable behavior AND you aren't executing code inside the object you are cleaning. – Bill K Dec 04 '09 at 17:50
4

They're not related. This is like asking, "Should you create objects in an initializer or in normal methods?" Like, it depends on what you're doing with the objects. A finalizer cleans up an object's state while it's destroyed (maybe — it's not something you should rely on), while a finally block executes code after a try block. There isn't any common situation where you'd be able to choose one or the other since they do different things.

Chuck
  • 234,037
  • 30
  • 302
  • 389
2

Finalize is probably a bad idea if your application causes lots of these objects to be created. This is because finalize will cause a bottleneck as the objects become eligible for garbage collection.

There are times when finalize is the only solution; but use finally whenever you can

oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
2

Finally. Finalize is bad in that it may never get called. Use finalize only as a safety net. For example an InputStream should have a finalize that closes the stream incase the applcicationforgets to. However the application should close it.

If it were me I would do the cleanup in the finalizer as well and log the cases when the cleanup was performed and then track down in the application the code that forgot to properly clean up.

TofuBeer
  • 60,850
  • 18
  • 118
  • 163
1

There are a number of problems with the code in the question, including:

  • The big problem: It looks like you are trying to close a socket. Even if you don't close it properly, it will close in its own finaliser. Adding another finaliser doesn't make it any more closed.
  • An exception thrown by the first close will prevent the others from executing (as it happens, this doesn't matter in this example because of the peculiar behaviour of Socket).
  • If you do override finalize, leave it throwing Throwable (and add @Override). Technically you should also call the super in a finally block.
  • The Java Memory Model is mighty strange when it comes to finalisers (previous execution of code does not necessarily happen-before the execution of the finaliser). I would explain the problem, but what you need to know is that you need to stay away from finalisers.

So: Always use finally for these things. finalize is extremely specialised (and PhantomReference are probably better is superficially more complicated).

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
0

If you are looking for alternatives to finalize() the proper question would be:

  • Why use an explicit close() method like, for example, all the stream and writer/reader classes in java.io.* and many others - when there is finalize()?

The other answers make it clear that the disadvantage of finalize() is that you have no way to force it to run, and neither do any who might use your code.

Of course, calling a close() methode (best done in a finally block or in a close() method itself) has to be documented by the author and then remembered to be called by the ones using the code. But there are lots of examples (not only java.io.*) where this is imposed and it works.

BTW: close() is merely a convention.

Risadinha
  • 16,058
  • 2
  • 88
  • 91
0

Joshua Bloch makes a very clear recommendation in his book Effective Java (2nd Edition). Copied from chapter 2 Item 7: Avoid finalizers:

Finalizers are unpredictable, often dangerous, and generally unnecessary. Their use can cause erratic behavior, poor performance, and portability problems. Finalizers have a few valid uses, which we’ll cover later in this item, but as a rule of thumb, you should avoid finalizers.

Please read the reference to find out why.

matsev
  • 32,104
  • 16
  • 121
  • 156