Memory leak of java.util.ref.Finalizer while Finalizer thread is waiting

送分小仙女□ 提交于 2021-01-01 06:57:04

问题


Analysing a heap dump I look for instances of java.lang.ref.Finalizer class. java.lang.ref.Finalizer has 'next' and 'prev' member fields for maintaining linked list. I always get FileInputStream as a tail of the list and FileOutputStream as previous entry to it (analysed several heap dumps). File descriptors for FileInputStream and FileOutputStream are always 0 and 1 respectively:

+---[Pending Finalization] java.lang.ref.Finalizer           
| |                                                          
| +---queue  java.lang.ref.ReferenceQueue [Stack Local]      
| |                                                          
| +---referent  java.io.FileInputStream                     
| | |                                                        
| | +---closed = boolean false                               
| | |                                                        
| | +---closeLock  java.lang.Object                          
| | |                                                        
| | +---fd  java.io.FileDescriptor                           
| |   |                                                      
| |   +---closed = boolean false                             
| |   |                                                      
| |   +---fd = int 0                                         
| |   |                                                       
| |   +---parent  java.io.FileInputStream                    
| |                                                          
| +---prev  [Pending Finalization] java.lang.ref.Finalizer   
|   |                                                        
|   +---queue  java.lang.ref.ReferenceQueue [Stack Local]    
|   |                                                        
|   +---next  [Pending Finalization] java.lang.ref.Finalizer 
|   |                                                        
|   +---referent  java.io.FileOutputStream                   
|   | |                                                      
|   | +---append = boolean false                             
|   | |                                                      
|   | +---closed = boolean false                             
|   | |                                                       
|   | +---closeLock  java.lang.Object                        
|   | |                                                     
|   | +---fd  java.io.FileDescriptor                         
|   |   |                                                    
|   |   +---closed = boolean false                           
|   |   |                                                    
|   |   +---fd = int 1  0x00000001                           
|   |   |                                                    
|   |   +---parent  java.io.FileOutputStream                 
|   |                                                         
|   +---prev  [Pending Finalization] java.lang.ref.Finalizer 
  1. Why always FileInputStream and FileOutputStream are at the tail of the ReferenceQueue?
  2. Aren't they collected by garbage collector because I observe only Allocation Failure GC not Full GC occuring?
  3. Why descriptors are always 0 and 1 for them?

回答1:


Maybe the following test program will shed some light on it:

Field fd = FileDescriptor.class.getDeclaredField("fd");
fd.setAccessible(true);
System.out.println("stdin:  "+fd.get(FileDescriptor.in));
System.out.println("stdout: "+fd.get(FileDescriptor.out));
System.out.println("stderr: "+fd.get(FileDescriptor.err));
stdin:  0
stdout: 1
stderr: 2

Ideone, Note that for JDK 8, this applies to Unix like systems only

In other words, you are looking at the file streams encapsulated by System.in and System.out and, of course, these will never get garbage-collected and usually, you also don’t call close() on them.

The finalization does not support any kind of opt-out, so any instance of a class with a “non trivial finalize() method” will get a finalizer reference upon construction, even when the creator knows that the object will never get finalized.

The most recent JDK versions use a Cleaner for this purpose, which allows not to register a cleaner when a FileInputStream or FileOutputStream is constructed using an existing FileDescriptor, which is the case for stdin and stdout. It also allows immediate cleaning and hence deregistration in the close() method, not needing any post-mortem cleanup for well behaved programs.

So with the newest Java versions, you should see only cleaners for streams actually in use in the heap dump.



来源:https://stackoverflow.com/questions/54822835/memory-leak-of-java-util-ref-finalizer-while-finalizer-thread-is-waiting

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!