Good uses of the finalize() method [duplicate]
Asked Answered
M

6

17

This is mostly out of curiosity.

I was wandering if anyone has encountered any good usage for Object.finalize() except for debugging/logging/profiling purposes ?

If you haven't encountered any what would you say a good usage would be ?

Marcellemarcellina answered 18/11, 2010 at 13:13 Comment(2)
You can use it as a door stop, or a boat anchor :-)Leaven
:D you mean its heavy enough or that it doesn't float ?Marcellemarcellina
S
11

If your Java object uses JNI to instruct native code to allocate native memory, you need to use finalize to make sure it gets freed.

Suctorial answered 18/11, 2010 at 13:14 Comment(9)
Does someone out there disagree with this?Suctorial
Why can't you just handle native memory like all other resources (open files, DB connections) and require explicit closing? Your Java object could just have a dispose() or close() that does the cleanup.Hairstreak
THose things generally have finalizers. 'close()' allows you to get the resources freed sooner, but the JVM still uses a finalizer to guarantee that they get freed eventually.Suctorial
@sleske: Why don't we handle all objects this way? Obviously, because we don't have to. Other resources are scarce, so we must close them, but some native memory may be no problem, so we can handle it in the Java way.Clink
@Clink are you saying that using finalize() is “the Java way”, compared to using a “try with resource” or calling close() manually?Gause
@Gause No, not at all. The Java way of dealing with resources other than memory is obviously some half-manual prompt closing, but there might be cases when it doesn't apply as you don't know how long it'll be needed. At the same time, you usually have no other choice as you may too easily run out of these resources before the GC kicks in. +++ The native memory is the only example, where I can imagine, it's as abundant as heap memory and get the same treatment. +++ At the same time, I can't imagine any good use for such a scenario.Clink
@Clink we could handle native memory similarly to heap memory, if the JVM was able to detect that it is getting low, to trigger the GC. Otherwise, it’s still the case that lots of objects encapsulating native memory can be unreachable, but the GC doesn’t kick in because there’s plenty of heap memory available.Gause
@Gause Every native allocation could check free memory and possibly report back and this could trigger GC. However, such checks may be expensive and there are things like fragmentation..... +++ Native memory used for number crunching (which may be more efficient outside of Java) might work as an example.Clink
@Clink a simple strategy doesn’t have to be expensive. Just attempt the native allocation and only if it fails, run the gc, execute the cleaners and try again. However, this interacts with all native allocations, so each of them, including those inside the JVM code and within the native libraries would have to follow this principle, which can’t work 100%, as some libraries are actually not Java specific. But some systems support registering callbacks, to be invoked after a failed memory allocation. For those, it could work.Gause
A
6

Late to the party here but thought I would still chime in:

One of the best uses I have found for finalizers is to call explicit termination methods which, for what ever reason, were not called. When this occurs, we also log the issue because it is a BUG!

Because:

  • There is no guarantee that finalizers will be executed promptly (or technically at all), per the language specification
  • Execution is largely dependent on the JVM implementation
  • Execution can sometimes be delayed if the GC has a lower thread priority

This leaves only a handful of tasks that they can address without much risk.

Antaeus answered 3/1, 2011 at 21:11 Comment(0)
A
3
  1. close external connections (db, socket etc)
  2. close open files. may be even try to write some additional information.
  3. logging
  4. if this class runs external processes that should exist only while object exists you can try to kill them here.

But it is just a fallback that is used is "normal" mechanism did not work. Normal mechanism should be initiated explicitly.

Addlepated answered 18/11, 2010 at 13:34 Comment(9)
Really important to use only as protection against buggy code. Operating systems limit the number of open files per process, you may run out of file handles long before the finalize() gets called.Swipe
Close open files on finalize ? Since finalize may never be called during the application lifetime are you sure this is a good idea ? I would say that you need to close open files in a finally block (or something that you are sure is executed).Marcellemarcellina
@Marcellemarcellina I think what AlexR meant was that these are fallbacks (like he said in his answer) in case for some reason the files were not closed when they were supposed to be, not that you avoid closing files altogether and let the finalizer handle it all the time.Pelson
Agreed, even if they are fallbacks however your file could be closed before it should be if you are closing it in a finalize method since there is now way to predict (and you shouldn't) when the garbage collection will run.Marcellemarcellina
I do this regularly myself. Should a caller set up a try/finally to make sure a file gets closed? Of course. But you can't be sure every programmer will do it right. Maybe there's a complex case where data is being passed between functions and it isn't practical. Having a finalizer as a fallback so the system keeps running despite a leak seems like a good idea.Giesecke
What I'm trying to say is that your finalize can be called immediately after application start (unlikely but has happened to me) which could close streams/external connections before your explicit code even has a chance to use them. That is what I mean by 'you can't predict when garbage collection will run'.Marcellemarcellina
@Marcellemarcellina how does your code work? A referenced object cannot be finalized, so your connection object is already unreachable at the time it is collected. So you could not use it either way. It could be a flaw that the finalizer of one object closes a shared connection, but that would be a bug of your code.Swipe
@Swipe If the finalize() is in the connection object then of course it is ok to use finalize as a fallback. What I mean is that if for instance you have a ConnectionManager with several connections inside as fields and you use the finalize() of the manager to close them, there might be references to the connections still used while you manager is no longer used and in this case you will kill the connections prematurely. This is valid IMHO in the case of streams since they are rarely extended (if ever), thats why I can't see a good use in closing a stream in a finalize.Marcellemarcellina
@Swipe recommended reads: finalize() called on strongly reachable objects in Java 8 and Can java finalize an object when it is still in scope?. Always keep in mind that the JVM may reclaim an object when it detects that its memory is not needed anymore, whereas native resources are often represented by a primitive value, like an int or long representing an address or handle. When optimized code keeps that primitive value in a CPU register, the object can be garbage collected.Gause
C
3

Release resources that should be released manually in normal circumstances, but were not released for some reason. Perhaps with write a warning to the log.

Conoscenti answered 18/11, 2010 at 13:44 Comment(1)
Ooh, writing to a log is a good idea. Then you not only get the thing released but you get some warning about the problem. I never thought of that. I have a class I should make that change to ...Giesecke
E
2

I use it to write back data to a database when using soft references for caching database-backed objects.

Ebullition answered 18/11, 2010 at 13:16 Comment(1)
You should let some library take care of these things.Ebullition
D
-1

I see one good use for finalize(): freeing resources that are available in large amounts and are not exclusive.

For example, by default there are 1024 file handles available for a Linux process and about 10000 for Windows. This is pretty much, so for most applications if you open a file, you don't have to call .close() (and use the ugly try...finally blocks), and you'll be OK - finally() will free it for you some time later. However for some pieces of code (like intensive server applications), releasing resources with .close() is a must, otherwise finally() may be called too late for you and you may run out of file handles.

The same technique is used by Swing - operating system resources for displaying windows and drawing aren't released by any .close() method, but just by finalize(), so you don't have to worry about all .close() or .dispose() methods like in SWT for example.

However, when there is very limited number of resources, or you must 'lock' resource to use it, also remember to 'unlock' it. For example if you create a file lock on a file, remember also to remove this lock, otherwise nobody else will be able to read or write this file and this can lead to deadlocks - then you can't rely on finalize() to remove this lock for you - you must do it manually at the right place.

Desmund answered 18/11, 2010 at 16:11 Comment(3)
-1: it is the height of rudeness for an application to rely on the finalizer to close a file handle, when it's so easy to call close().Clematis
calling .close() is not that easy at all: the 100%-correct handling of close requires two try... clauses (one try...finally to ivoke close(), and close() invocation should be enclosed with try...catch, which should then log the error to prevent loosing the original exception), the more files you are working on, the situation is worse, for example working with two files at the same time requires 4 try...catch blocks - what a mess now compare this with the ease of working with files in scripting languages, like Perl for example - you don't have to call close() in all the places!Desmund
This is fundamentally wrong. Native resources associated with an AWT/Swing window are freed when dispose() is called and only when dispose() is called. As long as a window is not explicitly disposed, it’s reachable via Window.getWindows() and will not get garbage collected. So its finalize() method would not get invoked, even if it had a finalizer. Further, the finalizer of a FileDescriptor will close the handle, but not flush any buffers. So not closing a file related resource can lead to data loss.Gause

© 2022 - 2024 — McMap. All rights reserved.