我刚刚接受了一次采访,被要求用 Java 创建内存泄漏。
不用说,我感觉很愚蠢,不知道如何开始创建一个。
举个例子是什么?
最佳答案
这是在纯 Java 中创建真正的内存泄漏(运行代码无法访问但仍存储在内存中的对象)的好方法:
- 应用程序创建一个长时间运行的线程(或使用线程池来更快地泄漏)。
- 线程通过(可选自定义)
ClassLoader
加载类。 - 该类分配一大块内存(例如
new byte[1000000]
),在静态字段中存储对其的强引用,然后在中存储对其自身的引用线程本地
。分配额外的内存是可选的(泄漏类实例就足够了),但它会使泄漏工作更快。 - 应用程序会清除对自定义类或从中加载它的
ClassLoader
的所有引用。 - 重复。
由于 ThreadLocal
在 Oracle JDK 中的实现方式,这会造成内存泄漏:
- 每个
Thread
都有一个私有(private)字段threadLocals
,它实际上存储线程本地值。 - 此映射中的每个键都是对
ThreadLocal
对象的弱引用,因此在该ThreadLocal
对象被垃圾收集之后,其条目已从 map 中删除。 - 但是每个值都是一个强引用,因此当一个值(直接或间接)指向
ThreadLocal
对象时,它就是它的键 ,只要线程存在,该对象就不会被垃圾收集,也不会从映射中删除。
在此示例中,强引用链如下所示:
Thread
对象 → threadLocals
映射 → 示例类实例 → 示例类 → 静态 ThreadLocal
字段 → ThreadLocal
对象。
(ClassLoader
在创建泄漏方面并没有真正发挥作用,它只是因为这个额外的引用链而使泄漏变得更糟:示例类 → ClassLoader
→它加载的所有类。在许多 JVM 实现中情况甚至更糟,尤其是在 Java 7 之前,因为类和 ClassLoader 被直接分配到 permgen 中并且根本不会被垃圾回收。)
这种模式的一个变体是,如果您经常重新部署恰好使用以某种方式指向自身的 ThreadLocal 的应用程序,那么应用程序容器(如 Tomcat)可能会像筛子一样泄漏内存。发生这种情况的原因有很多微妙的原因,并且通常很难调试和/或修复。
更新:由于很多人不断要求,here's some example code that shows this behavior in action .
关于java - 如何在 Java 中造成内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17160737/