views:

16558

answers:

13

Is there a destructor for Java? I don't seem to be able to find any documentation on this. If there isn't, how can I achieve the same effect?

Thank you in advance.

EDIT: First of all I thank everyone for swift reply. I see a lot of very good answers there. To make my question more specific, I am writing an application that deals with data, and the specification say that there should be a 'reset' button that brings the application back to its original just launched state. However, all data have to be 'live' unless application is closed or reset button is pressed.

Being usually a C/C++ programmer, I thought this would be trivial to implement. (And hence I planned to implement it last.) I structured my program such that all the 'reset-able' objects would be in a same class so that I can just destroy all 'live' objects when reset button is pressed.

I was thinking, if all I did was just to dereference the data and wait for the garbage collector to collect them, wouldn't there be a memory leak if my user repeatedly entered data and pressed the reset button? I was also thinking, since Java is quite mature as a language, there should be a way to prevent this from happening or gracefully tackle this.

Once again, thank you all for kind attention. Appreciated.

+1  A: 

No. Object#finalize is the closest you can get. However, when (and if) is is called is not guaranteed. See System#runFinalizersOnExit

flicken
A: 

The finalize() function is the destructor.

However, it should not be normally used because it is invoked after the GC and you can't tell when that will happen (if ever).

Moreover, it takes more than one GC to deallocate objects that have finalize().

You should try to clean up in the logical places in your code using the try{} finally{} statements!

Shimi Bandiel
+27  A: 

Because Java is a garbage collected language you cannot predict when (or even if) an object will be destroyed. Hence there is no direct equivalent of a destructor.

There is an inherited method called finalize, but this is called entirely at the discretion of the garbage collector. So for classes that need explicit tidy up the convention is to define a close method and use finalize only for sanity checking (i.e. if close has not been called do it now and log an error).

There was a question that spawned in-depth discussion of finalize recently, so that should provide more depth if required...

Garth Gilmour
A: 

The closest equivalent to a destructor in Java is the finalize() method. The big difference to a traditional destructor is that you can't be sure when it'll be called, since that's the responsibility of the garbage collector. I'd strongly recommend carefully reading up on this before using it, since your typical RAIA patterns for file handles and so on won't work reliably with finalize().

Nik
+14  A: 

Nope, no destructors here. The reason is that all Java objects are heap allocated and garbage collected. Without explicit deallocation (i.e. C++'s delete operator) there is no sensible way to implement real destructors.

Java does support finalizers, but they are meant to be used only as a safeguard for objects holding a handle to native resources (i.e. sockets, file handles, window handles, etc.) When the garbage collector collects an object without a finalizer it simply marks the memory region as free and that's it. When the object has a finalizer, it's first copied into a temporary location (remember, we're garbage collecting here), then it's enqueued into a waiting-to-be-finalized queue and then a Finalizer thread polls the queue with very low priority and runs the finalizer.

All Finalizers are run in the same thread, so if any of the finalizers hangs, the whole finalizer thread hangs. If you throw an exception, this will kill the finalizer thread and no further pending objects would be finalized. When the application exits, the JVM stops without waiting for the pending objects to be finalized, so there practically no guarantees that your finalizers will ever run.

ddimitrov
+4  A: 

Use of finalize() methods should be avoided. They are not a reliable mechanism for resource clean up and it is possible to cause problems in the garbage collector by abusing them.

If you require a deallocation call in your object, say to release resources, use an explicit method call. This convention can be seen in existing APIs (e.g. Closeable, Graphics.dispose(), Widget.dispose()) and is usually called via try/finally.

Resource r = new Resource();
try {
    //work
} finally {
    r.dispose();
}

Attempts to use a disposed object should throw a runtime exception (see IllegalStateException).


EDIT:

I was thinking, if all I did was just to dereference the data and wait for the garbage collector to collect them, wouldn't there be a memory leak if my user repeatedly entered data and pressed the reset button?

Generally, all you need to do is dereference the objects - at least, this is the way it is supposed to work. If you are worried about garbage collection, check out Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning (or the equivalent document for your JVM version).

McDowell
+1  A: 

Perhaps you can use a try ... finally block to finalize the object in the control flow at which you are using the object. Of course it doesn't happen automatically, but neither does destruction in C++. You often see closing of resources in the finally block.

jlouis
This is the right answer when the resource in question has a single owner and never has references to it "stolen" by other code.
Steve Jessop
+3  A: 

I fully agree to other answers, saying not to rely on the execution of finalize.

In addition to try-catch-finally blocks, you may use Runtime#addShutdownHook (introduced in Java 1.6) to perform final cleanups in your program.

That isn't the same as destructors are, but one may implement a shutdown hook having listener objects registered on which cleanup methods (close persistent database connections, remove file locks, and so on) can be invoked - things that would normally be done in destructors. Again - this is not a replacement for constructors but in some cases you can approach the wanted functionality with this.

The advantage of this is having deconstruction bevaviour loosley coupled from the rest of your program.

Markus Lux
addShutdownHook was apparently introduced in Java 1.3. Anyway, it's available to me in 1.5. :) See this: http://stackoverflow.com/questions/727151/how-do-i-cleanup-an-opened-process-in-java
skiphoppy
+4  A: 

First, note that since Java is garbage-collected, it is rare to need to do anything about object destruction. Firstly because you don't usually have any managed resources to free, and secondly because you can't predict when or if it will happen, so it's inappropriate for things that you need to occur "as soon as nobody is using my object any more".

You can be notified after an object has been destroyed using java.lang.ref.PhantomReference (actually, saying it has been destroyed may be slightly inaccurate, but if a phantom reference to it is queued then it's no longer recoverable, which usually amounts to the same thing). A common use is:

  • Separate out the resource(s) in your class that need to be destructed into another helper object (note that if all you're doing is closing a connection, which is a common case, you don't need to write a new class: the connection to be closed would be the "helper object" in that case).
  • When you create your main object, create also a PhantomReference to it. Either have this refer to the new helper object, or set up a map from PhantomReference objects to their corresponding helper objects.
  • After the main object is collected, the PhantomReference is queued (or rather it may be queued - like finalizers there is no guarantee it ever will be, for example if the VM exits then it won't wait). Make sure you're processing its queue (either in a special thread or from time to time). Because of the hard reference to the helper object, the helper object has not yet been collected. So do whatever cleanup you like on the helper object, then discard the PhantomReference and the helper will eventually be collected too.

There is also finalize(), which looks like a destructor but doesn't behave like one. It's usually not a good option.

Steve Jessop
+2  A: 

If it's just memory you are worried about, don't. Just trust the GC it does a decent job. I actually saw something about it being so efficient that it could be better for performance to create heaps of tiny objects than to utilize large arrays in some instances.

John Nilsson
A: 

Though there have been considerable advancements in Java's GC technology, you still need to be mindful of your references. Numerous cases of seemingly trivial reference patterns that are actually rats nests under the hood come to mind.

From your post it doesn't sound like you're trying to implement a reset method for the purpose of object reuse (true?). Are your objects holding any other type of resources that need to be cleaned up (i.e., streams that must be closed, any pooled or borrowed objects that must be returned)? If the only thing you're worried about is memory dealloc then I would reconsider my object structure and attempt to verify that my objects are self contained structures that will be cleaned up at GC time.

tyler
A: 

I am sorry if this strays from the main topic, but java.util.Timer (SE6) documentation says:

"After the last live reference to a Timer object goes away and all outstanding tasks have completed execution, the timer's task execution thread terminates gracefully (and becomes subject to garbage collection). However, this can take arbitrarily long to occur. By default, the task execution thread does not run as a daemon thread, so it is capable of keeping an application from terminating. If a caller wants to terminate a timer's task execution thread rapidly, the caller should invoke the timer's cancel method..."

I would like to call cancel upon the class owning the Timer losing its last reference(or immeditalesky before). Here a reliable destructor could do that for me. The comments above indicate that finally is a poor choice, but is there an elegant solution? That business of "...capable of keeping an application from terminating..." is not appealing.

A: 

If you're writing a Java Applet, you can override the Applet "destroy()" method. It is...

 * Called by the browser or applet viewer to inform
 * this applet that it is being reclaimed and that it should destroy
 * any resources that it has allocated. The stop() method
 * will always be called before destroy().

Obviously not what you want, but might be what other people are looking for.