Basic Preparation related knowledge
1 Java GC is only responsible for memory-related cleanup, and all other resource cleanup must be done manually by the programmer. Otherwise, it can cause a resource leak, which could cause the program to crash.
2 Calling the GC does not guarantee that the GC is actually executing.
3 Finalize throws an uncaught exception that causes only the finalize execution of the object to exit.
4 users can call the Finalize method of an object themselves, but this call is a normal method call, independent of the object's destruction process.
5 The JVM guarantees that the method must be called if it implements the Finalize method before the memory occupied by an object is reclaimed. The default finalize of object does nothing, for efficiency, the GC can assume that a finalize does not exist.
The finalize call chain for 6 objects, like the clone call chain, must be constructed manually
protected void throws throwable { Super. Finalize ();}
the destruction process of the object
In the process of object destruction, according to the implementation of the object's finalize, can be divided into the following, the system will record the corresponding state of the object:
Unfinalized does not perform finalize and the system is not ready to execute.
Finalizable can perform finalize, and the system will perform finalize at a later time.
Finalized the object's finalize has been executed.
How does the GC keep track of Finalizable objects? The GC has a queue called F-queue, and all objects are added to the queue when they become finalizable, and then wait for the GC to execute its Finalize method.
At this point we introduced another sort of record for the object, and the system can check which one the object belongs to.
Reachable the object that the chain can reach from the active object reference. Includes local variables for all threads on the current stack, all static variables, and so on.
Finalizer-reachable the object that can be reached by reference, except reachable, from F-queue.
Unreachable the other objects.
Take a look at the state transition diagram of the object.
1 First, all objects are from the reachable+unfinalized to the road of death.
2 when the object is unreachable from the current activity set, the object can be changed from the reachable state to the f-reachable or unreachable state.
3 When the object is non-reachable+unfinalized, the GC moves it into the f-queue and the state changes to f-reachable+finalizable.
4 Okay, the key comes, at any time, the GC can get a Finalizable object from F-queue, mark it as finalized, and then execute its Finalize method, because the object is reachable in this thread, The object then becomes reachable (and finalized). When the Finalize method executes, it is possible to turn other f-reachable objects into a reachable, which is called object regeneration.
5 When an object is in Unreachable+unfinalized, if the object uses a finalize of the default object, or though it is rewritten, the new implementation does nothing. For performance, the GC can change the object to the reclaimed state directly and destroy it without adding to the f-queue to wait for the GC to do further processing.
6 from the state diagram, no matter how the toss, the finalize of any object is executed at most once, once the object becomes finalized, it will not go back to f-queue. Of course there is no chance to perform finalize again.
7 when the object is in Unreachable+finalized, the object is not far from the real death. The GC can safely reclaim the object's memory. Enter the reclaimed.
Examples of Object Rebirth
classC {StaticA; } classA {b b; PublicA (b b) { This. B =b; } @Override Public voidFinalize () {System.out.println ("A Finalize"); C.A= This; } } classB {String name; intAge ; PublicB (String name,intAge ) { This. Name =name; This. Age =Age ; } @Override Public voidFinalize () {System.out.println ("B Finalize"); } @Override PublicString toString () {returnName + "is" +Age ; } } Public classMain { Public Static voidMain (string[] args)throwsException {A A=NewANewB ("Allen", 20)); A=NULL; System.GC (); Thread.Sleep (5000); System.out.println (C.A.B); } }
Expected output
A Finalize
B Finalize
Allen is 20
But it is possible to fail, stemming from GC uncertainties and timing problems, and running multiple times should be successful. Refer to the reference document at the end of this article for detailed explanation.
The order in which the finalize of the object is executed
The execution of finalize for all finalizable objects is indeterminate, not determined by which thread to execute, nor is the order of execution determined.
Consider the following situations to understand why, instance A,b,c is a set of finalizable objects that are referred to each other as loops.
When and how to use Finalize
From the above analysis, draw a conclusion.
1 most important, try not to use finalize, too complicated, or let the system care better. Other methods can be defined to release non-memory resources.
2 if used, as simple as possible.
3 If use, avoid object regeneration, this is oneself to find trouble.
4 can be used to protect non-memory resources from being freed. Even if we define other methods to release non-memory resources, others may not call the method to release. In finalize it can be checked, if not released to release, the late release is better than not release.
5 There is no guarantee that the object will be destroyed, even if the object's finalize is already running. To implement some actions that ensure that objects are completely destroyed, you can only rely on the class and GC interactions in Java.lang.ref.
Understanding the Finalize for Java