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