我刚刚接受了一次面试,我被要求用 Java 创建一个内存泄漏。
不用说,我什至不知道如何开始创建一个,感觉很愚蠢。
有什么例子?
最佳答案
这是在纯 Java 中创建真正的内存泄漏(运行代码无法访问但仍存储在内存中的对象)的好方法:
- 应用程序创建一个长时间运行的线程(或使用线程池更快地泄漏)。
- 线程通过(可选自定义)
ClassLoader
加载一个类。 - 该类分配一大块内存(例如
new byte[1000000]
),在静态字段中存储对它的强引用,然后在中存储对自身的引用线程本地
。分配额外的内存是可选的(泄漏类实例就足够了),但它会使泄漏工作得更快。 - 应用程序清除对自定义类或从中加载它的
ClassLoader
的所有引用。 - 重复。
由于 ThreadLocal
在 Oracle 的 JDK 中实现的方式,这会造成内存泄漏:
- 每个
Thread
都有一个私有(private)字段threadLocals
,它实际上存储了线程局部值。 - 此映射中的每个 key 都是对
ThreadLocal
对象的弱引用,因此在该ThreadLocal
对象被垃圾回收之后,它的条目已从 map 中移除。 - 但每个值都是强引用,所以当一个值(直接或间接)指向
ThreadLocal
对象时,即是它的key ,只要线程存在,该对象就不会被垃圾收集或从 map 中删除。
在本例中,强引用链如下所示:
Thread
对象 → threadLocals
映射 → 示例类的实例 → 示例类 → 静态 ThreadLocal
字段 → ThreadLocal
对象。
(ClassLoader
并没有真正起到造成泄漏的作用,它只是因为这个额外的引用链而使泄漏变得更糟:example class → 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/6470651/