My previous blog:System.GC () and-XX:+DISABLEEXPLICITGC startup parameters, and Directbytebuffer memory release when discussing how to reclaim out-of-heap memory, mention "NiO in direct The release of memory is not through Finalize (), because finalize is unsafe and affects energy ". Effective Java is also mentioned in the book: Avoid finalizers. People have a latent sense of rebellion, others give the conclusion or the norm, unless there is enough reason to persuade you, unless you understand the reasons behind it, otherwise it can only be rote memorization, no image in-depth understanding, can not learn the real thing. This article through their own understanding and some practical examples, and everyone together more image of the understanding of finalize. or the classic word "Talking is cheap,show me the code".
Let's take a look at testobjecthasfinalize. This class provides a Finalize method
Package Finalize;public class Testobjecthasfinalize{public static void Main (string[] args) {while (true) { Testobjecthasfinalize heap = new Testobjecthasfinalize (); System.out.println ("Memory address=" + heap);}} @Overrideprotected void Finalize () throws Throwable{super.finalize (); System.out.println ("Finalize.");}}
Run the program and use the Jmap command to view the memory used by the object.
C:\Documents and settings\administrator>jps4232 Jps3236 testobjecthasfinalize5272c:\documents and Settings\ Administrator>jmap-histo:live 3236 num #instances #bytes class name-------------------------------------- --------1:106983 3423456 java.lang.ref.Finalizer 2:106977 855816 finalize. Testobjecthasfinalize 3:642 841384 [I 4:5204 521984 <constMethodKlass> 5:8678 460712 <symbolKlass> 6:5204 460672 <methodKlass> 7: 1694 206832 [C 8:351 206024 <constantPoolKlass> 9:351 142864 &L t;instanceklassklass> 10:325 140040 <constantPoolCacheKlass> 11:421 796 [B 12:1701 40824 java.lang.String 13:420 40320 java.lang.Class 14: 519 33720 [S 15:547 32800 [[I 16:758 24256 java.util.treemap$entry 17:94 18024 <metho ddataklass> 18:40 13120 <objArrayKlassKlass> 19:312 12776 [Ljava.lan G.object; 20:76 6080 java.lang.reflect.Method 21:181 5840 [Ljava.lang.String; 22:37 2664 Java.lang.reflect.Field 23:8 2624 <typeArrayKlassKlass>
you can see that the Java.lang.ref.Finalizer objects and testobjecthasfinalize are more memory-intensive, why are there so many finalizer objects? Why do you want so many testobjecthasfinalize objects? Similarly, we look at cases where there is no Finalize () method
public class Testobjectnofinalize{public static void Main (string[] args) {while (true) {testobjectnofinalize heap = new Tes Tobjectnofinalize (); System.out.println ("Object no Finalize Method." + heap);}}
C:\Documents and settings\administrator>jps4436 TestObjectNoFinalize6012 jps5272c:\documents and Settings\ administrator>jmap-histo:live 4436 num #instances #bytes class name-------------------------------------- --------1:5203 521896 <constMethodKlass> 2:8677 460696 <symbolklass> ; 3:5203 460584 <methodKlass> 4:1689 206544 [C 5:351 2059 <constantPoolKlass> 6:351 142864 <instanceKlassKlass> 7:325 140 024 <constantPoolCacheKlass> 8:421 79640 [B 9:1696 40704 java.lang.Str ing 10:420 40320 java.lang.Class 11:519 33720 [S 12:547 3 2800 [[i 13:758 24256 java.util.treemap$entry 14:407 22088 [i 15: 14720 <methoddataklass> 16:40 13120 <objArrayKlassKlass> 17:312 12776 [Ljava.lang.Ob ject; 18:76 6080 java.lang.reflect.Method 19:181 5840 [Ljava.lang.String; 20:37 2664 Java.lang.reflect.Field 21:8 2624 <typeArrayKlassKlass> 22:100 1976 [Ljava.lang.Class; 23:20 1664 [Ljava.util.hashmap$entry; 24:12 1440 <klassKlass> 25:59 1416 java.util.hashtable$entry 26: 728 Java.net.URL 27:18 720 java.util.HashMap 28:7 680 [Ljava.util.hashtable$entry; 29:6 672 java.lang.Thread 30:10 640 Java.lang.reflect.Constructor
It can be found that Java.lang.ref.Finalizer and testobjecthasfinalize do not occupy a lot of heap memory.
classes that do not provide a finalize () method consume less heap memory, are garbage collected faster, and the JVM does not create so many Java.lang.ref.Finalizer objects .
1. Using finalize can lead to significant memory consumption and performance loss
"Effective Java" mentions that "using finalizer can cause serious performance damage." In my machine, the practice of creating and destroying a simple object is approximately 5.6ns, increasing the finalizer time to 2400ns. In other words, creating and destroying objects with finalizer is 430 times times slower. " Additional memory consumption This is quite obvious, because when using finalize, there are many more Java.lang.ref.Finalizer objects in the heap memory. Performance loss This can be concluded by analysis, because when finalize is used, heap memory resides on a large number of useless testobjecthasfinalize objects. Why are there so many testobjecthasfinalize objects? Quite simply, garbage collection slows down and objects are destroyed faster than objects are created. Why are there so many Java.lang.ref.Finalizer object objects? This is a mechanism inside the JVM that is used to ensure that finalize is called only once.
2. The JVM does not ensure that finalize will be executed and that the time to finalize it is uncertain.
From an object that becomes unreachable, to its finalizer, it may take any length of time. This means that you cannot perform any time-focused tasks in the finalizer. It is a serious error to rely on finalizer to close a file because the descriptor of the open file is a limited resource. The JVM will defer execution of finalizer, so a large number of files will be kept open and will fail when a program can no longer open the file.
Import Sun.misc.unsafe;public class revisedobjectinheap{private Long address = 0;private unsafe unsafe = getusafeinstance . Getunsafeinstance ();p ublic revisedobjectinheap () {address = Unsafe.allocatememory (2 * 1024 * 1024);} @Overrideprotected void Finalize () throws Throwable{super.finalize (); unsafe.freememory (address);} public static void Main (string[] args) {while (true) {revisedobjectinheap heap = new Revisedobjectinheap (); System.out.println ("Memory address=" + heap.address);}}
running this code will soon cause an out-of-heap memory overflow. Why is it? It is because the Revisedobjectinheap.finalize method cannot be executed in time, and the heap memory cannot be released in time. You can refer to one of my other blogs: using out-of-
heap memory in Java, things to remember about memory recycling and unresolved legacy issues
Of course, there are other problems with finalize, and you can refer to the effective Java for details. The next step is to introduce some theoretical knowledge of the JVM performing the Finalize method. Objects that implement finalize () are more time-consuming to create and recycle. when created, creates a new additional finalizer object that points to the newly created object. In the case of recycling, at least two GC is required.
Let's take a look at what happens when you create a new object, and the test steps are as follows:
1. Break breakpoints in the while loop of the 2 classes of testobjectnofinalize and Testobjecthasfinalize, in Java.lang.ref.Finalizer finalizer () and register () Hit the breakpoint.
2, respectively debug run testobjectnofinalize and testobjecthasfinalize, observe the number of times to enter the finalizer breakpoint
The test results are as follows:
1. Testobjectnofinalize no Finalize () method
the number of finalizer breakpoints is very small (3 times, pointing to Jarfile, Inflater, FileInputStream), then entering a breakpoint in the while loop and no longer entering the breakpoint in finalizer. That is: when you create a Testobjectnofinalize object, the corresponding finalizer object is not created.
2, Testobjecthasfinalize provides the Finalize () method
Each time you create a Testobjecthasfinalize object, the corresponding finalizer object is created to point to it.
Then look at what happens when the object is recycled: Add the-xx:+printgcdetails parameter and observe the garbage collection process.
You can see that the testobjectnofinalize is garbage collected in the Cenozoic, and the memory is quickly reclaimed.
After several generations of memory testobjecthasfinalize, the full GC is frequently performed. This is thought to reclaim memory too slowly, resulting in new generation of memory can not be released in a timely manner, so the full GC must be expected to obtain free memory space. Although this experiment does not directly demonstrate the need for at least 2 GC, it is clear that objects with Finalize () garbage collection can be slow.
Some summaries of the finalize mechanism:
1. If a class A implements the Finalize () method, a finalizer object (pointing to the newly created object) will be created each time a Class A object is created, and if the class does not implement the Finalize () method, no additional Finalizer Object
2, finalizer internal maintenance of a unfinalized linked list, each time the creation of finalizer objects are inserted into the linked list. The source code is as follows
Stores the Finalizer object's linked header pointer static private Finalizer unfinalized = Null;static Private Object lock = new Object ();p rivate Finali Zer next = null, Prev = null;private void Add () {synchronized (lock) {if (unfinalized! = null) {This.next = Unfinalized;un Finalized.prev = this;} unfinalized = this;}}
3. If the class does not implement the Finalize method, the object can be disposed of directly from heap memory when garbage collection is performed. This is the fastest and most efficient way
4, if the class implements the finalize method, when GC is performed, if an object is found to be java.lang.ref only. Finalizer the object reference, the finalizer object is added to the finalizer class's Reference queue (F-queue) and the node is removed from the unfinalized list. This process is done automatically by the JVM when it is in GC.
/* invoked by VM */private void Remove () {synchronized (lock) { if (unfinalized = = this) {if (This.next! = null) { unfinalized = This.next;} else { unfinalized = This.prev;} } if (this.next! = null) {This.next.prev = This.prev; } if (This.prev! = null) {this.prev.next = This.next; } This.next = this;/* Indicates that this has been finalized */ This.prev = this;}}
This is the F-queue queue, which holds the finalizer object static private Referencequeue queue = new Referencequeue ();
5. Objects containing finalize () are freed from memory and require at least two GC.
In the first GC, the object was detected only by the Finalizer reference, and the object was put into java.lang.ref.Finalizer.ReferenceQueue at this time, because the Finalizer reference, the object can not be GC. Java.lang.ref.finalizer$finalizerthread will constantly clean up the queue object, remove the current element, and execute the object's Finalize method. After cleanup, the object does not have any references, and the next GC is recycled.
6. Finalizer is a daemon thread inside the JVM, with a low priority. The finalizer thread is a single thread of responsibility. This thread keeps looping around for new objects in the Java.lang.ref.Finalizer.ReferenceQueue. Once a new object appears in the finalizer thread discovery queue, it pops up the object, calls its Finalize () method, removes the reference from the finalizer class, and the next time the GC executes, This finalizer instance, and the object it references, can be recycled back to garbage.
private static class Finalizerthread extends Thread {finalizerthread (Threadgroup g) { super (G, "Finalizer");} public void Run () {for (;;) {try { Finalizer f = (Finalizer) queue.remove (); F.runfinalizer ();} catch (Interruptedexception x) { continue;}}}}
7, using finalize easy to cause oom, because if the object is created quickly, then the recovery speed of the finalizer thread is not enough to create the speed, it will lead to more and more memory garbage
Concluding remarks: Finally finished, welcome you crossing product reading. Where there is no place or inaccurate, please feel free to comment.
Effective Java item7:avoid finalizers, explains why finalize is unsafe and does not recommend using