Effective Java Third edition--8. Avoid using the finalizer and cleaner mechanisms

Source: Internet
Author: User
Tags stack trace terminates

Tips
"Effective Java, third Edition" an English version has been published, the second edition of this book presumably many people have read, known as one of the four major Java books, but the second edition of 2009 published, to now nearly 8 years, but with Java 6, 7, 8, and even 9 of the release, the Java language has undergone profound changes.
In the first time here translated into Chinese version. For everyone to learn to share.

8. Avoid using the finalizer and cleaner mechanisms

The finalizer mechanism is unpredictable, often dangerous, and often unnecessary. Their use can lead to erratic behavior, poor performance, and portability problems. The finalizer mechanism has some special uses, which we'll cover later in this article, but should usually be avoided. Starting with Java 9, the finalizer mechanism has been deprecated, but is still used by the Java class Library. The cleaner mechanism in Java 9 replaces the finalizer mechanism. The cleaner mechanism is not as dangerous as the finalizer mechanism, but it is still unpredictable, slow and often unnecessary.

Remind C + + programmers not to take the finalizer or cleaner mechanism in Java as the equivalent of the C + + destructor. In C + +, the destructor is the normal way to reclaim the related resources of the object, which corresponds to the construction method. In Java, when an object becomes unreachable, the garbage collector reclaims the storage space associated with the object without requiring the developer to do extra work. The C + + destructor is also used to reclaim other non-memory resources. In Java, try-with-resources or try-finally blocks are used for this purpose (entry 9).

One drawback of the finalizer and cleaner mechanisms is that they cannot be guaranteed to execute in a timely manner [jls,12.6]. When an object becomes inaccessible, the period of time is arbitrarily long when the finalizer and cleaner mechanisms begin to run. This means that you should never finalizer and cleaner the mechanism to do any time sensitive (time-critical) thing. For example, relying on the finalizer and cleaner mechanisms to close a file is a serious error because the open file descriptor is a limited resource. If many files are opened due to delays in running the finalizer and cleaner mechanisms, the program may fail because it can no longer open files.

Timely implementation of finalizer and cleaner mechanism is a function of garbage collection algorithm, this algorithm is very different in different implementations. The behavior of the program depends on the timely execution of the finalizer and cleaner mechanisms, and its behavior may vary greatly. Such a program will work perfectly on the JVM you test, but it may fail on your most important customer's machine.

Late termination (finalization) is not just a theoretical issue. Provides a finalizer mechanism for a class to arbitrarily delay the recycling of its instances. A colleague debugged a long-running GUI application that was mysteriously killed by a outofmemoryerror error. The analysis shows that, at the time of its death, there are thousands of graphical objects waiting to be finalized and recycled on the finalizer mechanism queue of the application. Unfortunately, the finalizer mechanism thread runs at a lower priority than other application threads, so the object is recycled less quickly than it enters the queue. The language specification does not guarantee which thread executes the finalizer mechanism, so there is no lightweight way to prevent such problems in addition to avoiding the use of the finalizer mechanism. In this respect, the cleaner mechanism is better than the finalizer mechanism because the creator of the Java class can control the threads of its own cleaner mechanism, but the cleaner mechanism is still running in the background, running under the control of the garbage collector, but not guaranteed to be cleaned up in time.

The Java specification does not guarantee that the finalizer and cleaner mechanisms will run in a timely manner; it cannot even guarantee that they will run. When a program finishes, the finalizer and cleaner mechanisms on some unreachable objects are still not running. Therefore, you should not rely on the finalizer and cleaner mechanisms to update the persistence state. For example, relying on the finalizer and cleaner mechanisms to release a persistent lock on a shared resource, such as a database, is a good way to get the entire distributed system stuck.

Do not believe System.gc and System.runFinalization method. They may increase the chance that the finalizer and cleaner mechanisms will be executed, but there is no guarantee that they'll be executed. The two methods that once claimed to have made such assurances: System.runFinalizersOnExit and its twin brothers Runtime.runFinalizersOnExit , contain deadly flaws, and have been discarded for decades [threadstop].

Another problem with the finalizer mechanism is that, during the execution of the finalizer mechanism, an uncaught exception is ignored and the finalizer mechanism of the object terminates [JLS, 12.6]. An uncaught exception causes other objects to fall into a corrupt state (corrupt). If another thread tries to use such a corrupted object, it may cause arbitrary indeterminate behavior. Typically, an uncaught exception terminates the thread and prints the stack trace (stacktrace), but does not issue a warning if it occurs in the finalizer mechanism. The cleaner mechanism does not have this problem because a class library that uses the cleaner mechanism can control its threads.

Using the finalizer and cleaner mechanisms can cause serious performance damage. On my machine, create a simple AutoCloseable object, use Try-with-resources to close it, and let the garbage collector reclaim it for about 12 nanoseconds. Using the finalizer mechanism, the time is increased to 550 nanoseconds. In other words, using the finalizer mechanism to create and destroy objects is 50 times times slower. This is mainly because the finalizer mechanism hinders effective garbage collection. If you use them to clean up all instances of a class (about 500 nanoseconds per instance on my machine), then the cleaner mechanism is the same speed as the finalizer mechanism, but if they are used only as a security net (safety net), the cleaner mechanism is much faster. As described below. In this environment, it takes about 66 nanoseconds to create, clean and destroy an object on my machine, which means that if you don't use a safety net, you need to pay 5 times times (not 50 times times) insurance.

The finalizer mechanism has a serious security problem: they open your class for finalizer mechanism attacks. The idea of a finalizer mechanism attack is simple: If an exception is thrown from a construction method or its serialization-- readObjec T and readResolve Method (12th chapter)--The finalizer mechanism of the malicious subclass can run in the "aborted" (died on the vine) "On the part of the constructed object. The finalizer mechanism can record a reference to an object in a static character property, preventing it from being garbage collected. Once a defective object is logged, you can simply invoke any method on that object, and these methods should not be allowed to exist. Throwing exceptions from the construction method should be sufficient to prevent the object from appearing, but not in the presence of the finalizer mechanism. Such an attack would have dire consequences. The final class is not affected by the finalizer mechanism attack, because no one can write a malicious subclass of the final class. To protect the non-final class from the finalizer mechanism, write a final finalize method that does nothing.

So, what should you do? Encapsulates a resource (such as a file or thread) that needs to end for an object, rather than writing finalizer and cleaner mechanisms for that class? Let your class implement the AutoCloseable interface and require the client to invoke each instance of the Close method when it is no longer needed, usually using try-with-resources to ensure termination, even in case of an exception throw (entry 9). A noteworthy detail is that the instance must keep track of whether it has been closed: The Close method must record properties that are no longer valid in the object, and the other method must check the property and throw a IllegalStateException exception if the object is called after it is closed.

So what are the benefits of the finalizer and cleaner mechanisms? They may have two legitimate uses. One is as a security net (safety net), in case the owner of the resource ignores its close approach. While there is no guarantee that the finalizer and cleaner mechanisms will run quickly (or not at all), it is better to delay the release of resources than the client has done. If you are considering writing such a safety net finalizer mechanism, consider carefully whether such protection is worth the cost. Some Java library classes, such as,,, FileInputStream FileOutputStream ThreadPoolExecutor and java.sql.Connection , have finalizer mechanisms as security nets.

The second method of rational use of the cleaner mechanism is related to the local peer class (native peers). A local peer class is a local (non-Java) object that is delegated by a normal object. Because the local peer is not an ordinary Java object, the garbage collector does not know it, and when its Java peers are reclaimed, the local peers are not recycled. Assuming that performance is acceptable, and that local peers do not have critical resources, then the finalizer and cleaner mechanisms may be the right tool for this task. However, if performance is unacceptable, or if the local peer holds resources that must be recovered quickly, then the class should have a close method, as described earlier.

The

Cleaner mechanism is a bit tricky to use. The following is a simple class that demonstrates the functionality. Assume that the room object must be cleaned up before being recycled. The type class implements the autocloseable interface, and its automatic cleanup security net uses a cleaner mechanism, which is just an implementation detail. Unlike the finalizer mechanism, the cleaner mechanism does not pollute a class's public API:

An autocloseable class using a cleaner as a safety Netpublic class, implements autocloseable {private static fi    nal Cleaner Cleaner = Cleaner.create (); Resource that requires cleaning.    Must not refer to room! Private static class state implements Runnable {int. Numjunkpiles;//number of junk piles in the This hostel Stat        E (int numjunkpiles) {this.numjunkpiles = Numjunkpiles; }//invoked by Close method or cleaner @Override public void Run () {System.out.println ("            Cleaning ");        numjunkpiles = 0;    }}//The state of this-the-cleanable private final state state; Our cleanable.    Cleans the "when it's eligible for GC private final cleaner.cleanable cleanable;        Public Guest (int numjunkpiles) {state = new State (numjunkpiles);    Cleanable = Cleaner.register (this, state);    } @Override public void Close () {Cleanable.clean (); }} 

Static internal State classes have the resources needed to clean up the room with the cleaner mechanism. Here, it contains only numJunkPiles attributes, which represent the number of chaotic rooms. More realistically, it could be a final-modified long type pointer to a local peer class. Stateclass implements an Runnable interface that run can be called at most once, and can only be Room called when we register an instance with the cleaner mechanism in the constructor method State Cleanable . The run invocation of a method is triggered by the following two methods: Typically, a method called within a method of a call is Room close Cleanable clean fired. If the Room client does not call the method when the instance is eligible for garbage collection close , then the cleaner mechanism will (hopefully) invoke State the run method.

StateIt is important that an instance does not reference its Room instance. If it references, a loop is created that prevents the Room instance from being garbage collected (and automatically purged). Therefore, State it must be a static nested inner class, because a non-static inner class contains a reference to an instance of its host class (entry 24). Similarly, it is unwise to use lambda expressions because they are easy to get a reference to the host class object.

As we said before, Room The cleaner mechanism is only used as a safety net. If the customer Room places all the instances in the Try-with-resource block, they never need to be cleaned up automatically. A well behaved client is as follows:

public class Adult {    public static void main(String[] args) {        try (Room myRoom = new Room(7)) {            System.out.println("Goodbye");        }    }}

As you might expect, the run Adult program prints Goodbye the string and then prints the Cleaning room string. But what if it doesn't clean up its room when it's not a regular program?

public class Teenager {    public static void main(String[] args) {        new Room(99);        System.out.println("Peace out");    }}

You might expect it to print out and Peace out then print the Cleaning room string, but on my machine, it never prints Cleaning room a string; just the program exits. This is the unpredictability we talked about before. The specification of the Cleaner mechanism says: " System.exit cleanup behavior during a method is implementation-specific. There is no guarantee that the cleanup behavior is invoked. "Although the specification is not stated, it is also true for normal program exits. On my machine, System.gc() adding methods to Teenager classes is main enough to get the program to print before exiting, but there is Cleaning room no guarantee that you will see the same behavior on your machine.

In summary, do not use the cleaner mechanism, or the finalizers mechanism prior to the release of Java 9, except as a safety net or to terminate non-critical local resources. Even so, beware of uncertainties and performance impacts.

Effective Java Third edition--8. Avoid using the finalizer and cleaner mechanisms

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.