Finalizer线程正在等待时java.util.ref.Finalizer的内存泄漏 [英] Memory leak of java.util.ref.Finalizer while Finalizer thread is waiting

查看:242
本文介绍了Finalizer线程正在等待时java.util.ref.Finalizer的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

分析堆转储,我在寻找java.lang.ref.Finalizer类的实例. java.lang.ref.Finalizer具有"next"和"prev"成员字段,用于维护链接列表.我总是将FileInputStream作为列表的尾部,并将FileOutputStream作为其先前的条目(分析了几个堆转储). FileInputStream和FileOutputStream的文件描述符分别始终为0和1:

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. 为什么FileInputStream和FileOutputStream总是位于ReferenceQueue的尾部?
  2. 不是因为我观察到只有分配失败GC而不是Full GC发生,所以它们不是由垃圾收集器收集的吗?
  3. 为什么描述符始终为0和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

Idone ,请注意,对于JDK 8,这仅适用于类似Unix的系统

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

换句话说,您正在查看由System.inSystem.out封装的文件流,当然,它们永远不会被垃圾回收,通常,您也不会在它们上调用close().

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.

终结处理不支持任何类型的退出,因此具有非平凡的finalize()方法"的类的任何实例在构造时都将获得终结器引用,即使创建者知道该对象永远也不会得到最终确定.

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.

最新的JDK版本使用

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.

因此,对于最新的Java版本,您应该只看到堆转储中实际使用的流的清理程序.

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

这篇关于Finalizer线程正在等待时java.util.ref.Finalizer的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆