Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么ClassLoader创建的对象没有机会对自身进行垃圾收集_Java - Fatal编程技术网

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]条目
第二部分考虑“新URLClassLoader(…)…loadClass(…).NeWistStand())情景:

  • 在循环的第一次迭代中:
  • 脆弱的类#1是从URLClassLoader#1加载的
  • 调用脆弱的构造函数
  • Weakling.local#1静态变量从null设置为新的ThreadLocal实例#1
  • ThreadLocal WeakHashMap将更新以存储新的弱实例#1
  • 在循环的所有后续迭代中
  • 脆弱的类#n是从URLClassLoader#n加载的
  • 调用脆弱的构造函数
  • Weakling.local#n静态变量从null设置为新的ThreadLocal实例#n
  • ThreadLocal WeakHashMap将更新以存储新的弱实例
请注意,在最后一步中,ThreadLocal实例#1不是弱可引用的。这是因为以下参考链:

  • WeakHashMap值强烈引用弱实例#1
  • 弱实例#1通过Object.getClass()强烈引用弱类#1
  • 弱类#1通过静态类变量强烈引用ThreadLocal实例#1
只要循环继续运行,就会向ThreadLocal WeakHashMap添加更多条目,并且WeakHashMap中从值到键(从弱实例到ThreadLocal)的强引用链可以防止对其他过时条目进行垃圾收集

我修改了加载程序,使其迭代3次,然后等待用户输入。然后,我使用java-Xrunhprof:heap=dump和ctrl-pause/break生成了一个堆转储。以下是我对最终堆转储的分析:

首先,有三个脆弱的物体:

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