Java 为什么ClassLoader创建的对象没有机会对自身进行垃圾收集
我指的是这个代码示例,它在 到 工作正常,未检测到泄漏Java 为什么ClassLoader创建的对象没有机会对自身进行垃圾收集,java,Java,我指的是这个代码示例,它在 到 工作正常,未检测到泄漏 有人能解释为什么ClassLoader创建的对象没有机会进行自身垃圾收集吗?ThreadLocal机制在当前线程上有效地存储ThreadLocal实例到值的WeakHashMap。因此,如果ThreadLocal实例永远不会变为弱可引用,则该条目实际上会泄漏 有两种情况需要考虑。为了简化讨论,我们假设ThreadLocal实际上在Thread.currentThread()上存储了一个WeakHashMap;实际上,它使用了一种更复杂的机制
有人能解释为什么ClassLoader创建的对象没有机会进行自身垃圾收集吗?ThreadLocal机制在当前线程上有效地存储ThreadLocal实例到值的WeakHashMap。因此,如果ThreadLocal实例永远不会变为弱可引用,则该条目实际上会泄漏 有两种情况需要考虑。为了简化讨论,我们假设ThreadLocal实际上在Thread.currentThread()上存储了一个WeakHashMap;实际上,它使用了一种更复杂的机制,具有同等的效果 首先考虑“新弱化”情景:
- 在循环的第一次迭代中:
- 弱类是从系统类加载器加载的
- 调用脆弱的构造函数
- Weakling.local静态变量从null设置为新的ThreadLocal实例#1
- ThreadLocal WeakHashMap将更新以存储新的弱实例#1
- 在循环的所有后续迭代中:
- 弱类已经从系统类装入器中装入
- 调用脆弱的构造函数
- Weakling.local静态变量从旧ThreadLocal实例#1设置为新ThreadLocal实例#2。旧的ThreadLocal实例#1现在仅(弱地)被WeakHashMap引用
- ThreadLocal WeakHashMap将更新以存储新的弱实例。在此操作期间,WeakHashMap注意到旧ThreadLocal实例#1只能弱引用,因此它会在添加[ThreadLocal实例#2,弱引用#2]条目之前从映射中删除[ThreadLocal实例#1,弱引用#1]条目
- 在循环的第一次迭代中:
- 脆弱的类#1是从URLClassLoader#1加载的
- 调用脆弱的构造函数
- Weakling.local#1静态变量从null设置为新的ThreadLocal实例#1
- ThreadLocal WeakHashMap将更新以存储新的弱实例#1
- 在循环的所有后续迭代中
- 脆弱的类#n是从URLClassLoader#n加载的
- 调用脆弱的构造函数
- Weakling.local#n静态变量从null设置为新的ThreadLocal实例#n
- ThreadLocal WeakHashMap将更新以存储新的弱实例
- WeakHashMap值强烈引用弱实例#1
- 弱实例#1通过Object.getClass()强烈引用弱类#1
- 弱类#1通过静态类变量强烈引用ThreadLocal实例#1
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)
请注意,所有三个弱实例(500002a1、500003a4和500003e0)都是从三个不同的类实例(分别为50000296、5000039d和500003d9)创建的。查看第一个对象,我们可以看到它作为一个值保存在threadLocal映射中的entry对象中:
OBJ 500002a5 (sz=32, trace=300012, class=java.lang.ThreadLocal$ThreadLocalMap$Entry@5000014b)
referent 500002a4
queue 500009f6
value 500002a1
此处的引用是弱持有的值:
OBJ 500002a4 (sz=16, trace=300347, class=java.lang.ThreadLocal@50000125)
通过搜索,我们可以看到这个对象在静态文件中作为一个值保存
上述弱类的变量“local”:
CLS 50000296 (name=Weakling, trace=300280)
super 50000099
loader 5000017e
domain 50000289
static local 500002a4
static staticRef 500002a1
总之,对于这个脆弱的实例,我们有下面的强引用链循环,它可以防止它被垃圾收集
- WeakHashMap值(500002a5)强烈引用弱实例(500002a1)
- 弱实例(500002a1)通过Object.getClass()强烈引用弱类(50000296)
- 弱类(50000296)通过静态类变量强烈引用ThreadLocal实例(500002a4)
对其他虚弱物体进行类似的分析也会得出类似的结果。允许程序运行额外的迭代表明对象继续以这种方式累积。newInstance调用在类对象上。它是“新弱者”的反映。“new Weakling”版本的唯一区别是每次都使用相同的类/类加载器对象。使用“new Weakling”时,每次都使用系统类加载器加载的弱类,因此重复覆盖相同的静态变量。当使用“new URLClassLoader().loadClass().newInstance”时,将创建一个新的类加载器,加载一个新的类,并将一个新的静态变量从null初始化为ThreadLocal的实例。“并初始化一个新的静态变量…”:那么,您是想说,在应用程序中,将有N个静态“局部”变量,在循环的N次迭代之后,如果我使用“new URLClassLoader().loadClass().newInstance”?我已经更新了答案,并添加了一个使用HProf堆转储输出的具体示例。让我知道,如果有一些额外的细节,我可以提供。哇,非常完整的答案,很好的工作+1或者你可以重述你的问题或澄清我回答中你不理解的部分?
OBJ 500002a5 (sz=32, trace=300012, class=java.lang.ThreadLocal$ThreadLocalMap$Entry@5000014b)
referent 500002a4
queue 500009f6
value 500002a1
OBJ 500002a4 (sz=16, trace=300347, class=java.lang.ThreadLocal@50000125)
CLS 50000296 (name=Weakling, trace=300280)
super 50000099
loader 5000017e
domain 50000289
static local 500002a4
static staticRef 500002a1