Is there a destructor for Java?

2018-12-31 15:46发布

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?

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 the 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 the same class so that I can just destroy all 'live' objects when a 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.

20条回答
后来的你喜欢了谁
2楼-- · 2018-12-31 16:02

I agree with most of the answers.

You should not depend fully on either finalize or ShutdownHook

finalize

  1. JVM does not guaranty when this finalize() method will be invoked.

  2. finalize() gets called only once by GC thread if object revives itself from finalizing method than finalize will not be called again.

  3. In your application, you may have some live objects, on which garbage collection is never invoked.

  4. Any Exception is thrown by finalizing method is ignored by GC thread

  5. System.runFinalization(true) and Runtime.getRuntime().runFinalization(true) methods increase the probability of invoking finalize() method but now these two methods have been deprecated. These methods are very dangerous due to lack of thread safety and possible deadlock creation.

shutdownHooks

public void addShutdownHook(Thread hook)

Registers a new virtual-machine shutdown hook.

The Java virtual machine shuts down in response to two kinds of events:

  1. The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
  2. The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
  3. A shutdown hook is simply an initialized but unstarted thread. When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. When all the hooks have finished it will then run all uninvoked finalizers if finalization-on-exit has been enabled.
  4. Finally, the virtual machine will halt. Note that daemon threads will continue to run during the shutdown sequence, as will non-daemon threads if the shutdown was initiated by invoking the exit method.
  5. Shutdown hooks should also finish their work quickly. When a program invokes exit the expectation is that the virtual machine will promptly shut down and exit.

    But even Oracle documentation quoted that

In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly

This occurs when the virtual machine is terminated externally, for example with the SIGKILL signal on Unix or the TerminateProcess call on Microsoft Windows. The virtual machine may also abort if a native method goes awry by, for example, corrupting internal data structures or attempting to access nonexistent memory. If the virtual machine aborts then no guarantee can be made about whether or not any shutdown hooks will be run.

Conclusion : use try{} catch{} finally{} blocks appropriately and release critical resources in finally(} block. During release of resources in finally{} block, catch Exception and Throwable.

查看更多
零度萤火
3楼-- · 2018-12-31 16:05

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 behaviorloosely coupled from the rest of your program.

查看更多
栀子花@的思念
4楼-- · 2018-12-31 16:06

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.

查看更多
泛滥B
5楼-- · 2018-12-31 16:10

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

查看更多
低头抚发
6楼-- · 2018-12-31 16:10

If you use Java 7, have a look at the try-with-resources statement. For example:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  System.out.println(br.readLine());
} catch (Exception e) {
  ...
} finally {
  ...
}

Here the resource that is no longer needed is freed in the BufferedReader.close() method. You can create your own class that implements AutoCloseable and use it in a similar fashion.

This statement is more limited than finalize in terms of code structuring, but at the same time it makes the code simpler to understand and maintain. Also, there is no guarantee that a finalize method is called at all during the livetime of the application.

查看更多
旧人旧事旧时光
7楼-- · 2018-12-31 16:11

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

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.

查看更多
登录 后发表回答