下面是一个在纯Java中创建真正内存泄漏(运行代码无法访问但仍存储在内存中的对象)的好方法:
ClassLoader
加载一个类.new byte[1000000]
),在静态字段中存储对它的强引用,然后在ThreadLocal
中存储对自身的引用.分配额外的内存是可选的(泄漏类实例就足够了),但这会使泄漏工作更快.ClassLoader
的所有引用.由于在Oracle的JDK中实现ThreadLocal
的方式,这会造成内存泄漏:
Thread
都有一个私有字段threadLocals
,它实际上存储线程本地值.ThreadLocal
对象的弱引用,因此在对该ThreadLocal
对象进行垃圾收集后,其条目将从映射中删除.ThreadLocal
对象(即其key)时,只要线程存在,该对象就不会被垃圾收集,也不会从映射中移除.在本例中,强引用链如下所示:
对象→threadLocals
映射示例类→实例→示例类→静电字段→ThreadLocal
对象.
(ClassLoader
在创建泄漏中并没有真正起到作用,它只是因为这个额外的引用链:example类而使泄漏变得更严重.)→ ClassLoader
→ 它加载的所有类.在许多JVM实现中,情况甚至更糟,尤其是在Java 7之前,因为类和ClassLoader
被直接分配到permgen中,而且从未被垃圾收集过.)
这种模式的一个变化是,如果经常重新部署碰巧使用ThreadLocal
个以某种方式指向自身的应用程序,那么应用程序容器(如Tomcat)会像筛子一样泄漏内存.发生这种情况有很多微妙的原因,通常很难调试和/或修复.
Update:因为很多人一直要求,所以here's some example code that shows this behavior in action.