我指的是这个代码示例,该示例在http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6254531中报告
import java.net.URL;
class Loader {
public static void main(String[] args) throws Exception {
for (;;) {
System.gc();
System.out.print(".");
System.out.flush();
new java.net.URLClassLoader(
new URL[] { new java.io.File(".").toURL() },
ClassLoader.getSystemClassLoader().getParent()
).loadClass("Weakling").newInstance();
}
}
}
public class Weakling {
private static ThreadLocal<Object> local;
private static Weakling staticRef;
private Object var = new byte[1000*1000];
public Weakling() {
local = new ThreadLocal<Object>();
local.set(this);
staticRef = this;
}
@Override
protected void finalize() {
System.out.print("F");
System.out.flush();
}
}
Run Code Online (Sandbox Code Playgroud)
永远不会调用finalize.但是,如果我改变了
new java.net.URLClassLoader(
new URL[] { new java.io.File(".").toURL() },
ClassLoader.getSystemClassLoader().getParent()
).loadClass("Weakling").newInstance();
Run Code Online (Sandbox Code Playgroud)
至
new Weakling();
Run Code Online (Sandbox Code Playgroud)
它运行良好,没有检测到泄漏.
任何人都可以解释为什么ClassLoader创建的对象没有机会垃圾收集自己?
Bre*_*ail 22
ThreadLocal机制有效地在当前线程上存储ThreadLocal实例的WeakHashMap到值.因此,如果ThreadLocal实例永远不会变得弱引用,那么该条目将被有效泄露.
有两种情况需要考虑.为简单起见,我们假设ThreadLocal实际上在Thread.currentThread()上存储了WeakHashMap; 实际上,它使用了一种具有同等效果的更复杂的机制.
首先考虑"新Weakling"场景:
其次考虑"new URLClassLoader(...).loadClass(...).newInstance()"场景:
请注意,在此最后一步中,ThreadLocal实例#1 不是弱引用的.这是因为以下参考链:
只要循环继续运行,就会向ThreadLocal WeakHashMap添加更多条目,并且WeakHashMap中从值到密钥(Weakling实例到ThreadLocal)的强引用链可以防止对其他过时条目进行垃圾回收.
我修改了Loader程序迭代3次,然后等待用户输入.然后,我使用java -Xrunhprof生成堆转储:heap = dump和ctrl-pause/break.以下是我对最终堆转储的分析:
首先,有三个Weakling对象:
OBJ 500002a1 (sz=16, trace=300345, class=Weakling@50000296)
OBJ 500003a4 (sz=16, trace=300348, class=Weakling@5000039d)
OBJ 500003e0 (sz=16, trace=300342, class=Weakling@500003d9)
Run Code Online (Sandbox Code Playgroud)
请注意,所有三个Weakling实例(500002a1,500003a4和500003e0)都是从三个不同的类实例(分别为50000296,5000039d和500003d9)创建的.查看第一个对象,我们可以看到它作为threadLocal映射中的条目对象中的值保存:
OBJ 500002a5 (sz=32, trace=300012, class=java.lang.ThreadLocal$ThreadLocalMap$Entry@5000014b)
referent 500002a4
queue 500009f6
value 500002a1
Run Code Online (Sandbox Code Playgroud)
这里的指称是弱势地保持价值:
OBJ 500002a4 (sz=16, trace=300347, class=java.lang.ThreadLocal@50000125)
Run Code Online (Sandbox Code Playgroud)
在搜索中,我们可以看到此对象在上述Weakling类的静态变量"local"中保存为值:
CLS 50000296 (name=Weakling, trace=300280)
super 50000099
loader 5000017e
domain 50000289
static local 500002a4
static staticRef 500002a1
Run Code Online (Sandbox Code Playgroud)
总之,我们为这个Weakling实例提供了以下强引用链循环,它可以防止它被垃圾回收.
对其他Weakling对象的类似分析将显示类似的结果.允许程序运行以进行其他迭代表明对象继续以这种方式累积.