簡體   English   中英

Finalizer線程正在等待時java.util.ref.Finalizer的內存泄漏

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

分析堆轉儲時,我尋找java.lang.ref.Finalizer類的實例。 java.lang.ref.Finalizer具有“ next”和“ prev”成員字段,用於維護鏈接列表。 我總是將FileInputStream作為列表的尾部,並將FileOutputStream作為其先前的條目(分析了幾個堆轉儲)。 FileInputStream和FileOutputStream的文件描述符分別始終為0和1:

+---[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. 為什么總是FileInputStream和FileOutputStream在ReferenceQueue的尾部?
  2. 它們不是由垃圾收集器收集的,因為我僅觀察到分配失敗GC而不發生完全GC?
  3. 為什么描述符的值始終為0和1?

也許下面的測試程序可以為您提供一些啟示:

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 ,請注意,對於JDK 8,這僅適用於類似Unix的系統

換句話說,您正在查看由System.inSystem.out封裝的文件流,當然,這些文件流永遠不會被垃圾回收,通常,您也不會在它們上調用close()

終結處理不支持任何類型的退出,因此,即使創建者知道對象將永遠不會終結,具有“非平凡的finalize()方法”的類的任何實例在構造時都將獲得終結器引用。

為此,最新的JDK版本使用Cleaner器,當使用現有的FileDescriptor構造FileInputStreamFileOutputStream時,不允許使用Cleaner進行注冊,stdin和stdout就是這種情況。 它還允許立即清理,並因此可以在close()方法中取消注冊,而對於行為良好的程序不需要任何事后清理。

因此,對於最新的Java版本,您應該只看到堆轉儲中實際使用的流的清理程序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM