如何在Java中创建内存泄漏? [英] How can I create a memory leak in Java?
问题描述
我刚刚接受采访,并被要求使用Java创建 内存泄漏 .
I just had an interview, and I was asked to create a memory leak with Java.
不用说,我很笨,甚至不知道如何开始创建一个.
Needless to say, I felt pretty dumb having no clue on how to even start creating one.
一个例子是什么?
推荐答案
这是在纯Java中创建真正的内存泄漏(运行代码无法访问但仍存储在内存中的对象)的好方法:
Here's a good way to create a true memory leak (objects inaccessible by running code but still stored in memory) in pure Java:
- 应用程序将创建一个长期运行的线程(或使用线程池以更快地泄漏).
- 线程通过(可选)
ClassLoader
加载类. - 该类分配大量内存(例如
new byte[1000000]
),在静态字段中存储对它的强引用,然后在ThreadLocal
中存储对自身的引用.分配额外的内存是可选的(泄漏类实例就足够了),但这将使泄漏工作快得多. - 应用程序清除对自定义类或从其加载的
ClassLoader
的所有引用. - 重复.
- The application creates a long-running thread (or use a thread pool to leak even faster).
- The thread loads a class via an (optionally custom)
ClassLoader
. - The class allocates a large chunk of memory (e.g.
new byte[1000000]
), stores a strong reference to it in a static field, and then stores a reference to itself in aThreadLocal
. Allocating the extra memory is optional (leaking the class instance is enough), but it will make the leak work that much faster. - The application clears all references to the custom class or the
ClassLoader
it was loaded from. - Repeat.
由于在Oracle的JDK中实现ThreadLocal
的方式,这会导致内存泄漏:
Due to the way ThreadLocal
is implemented in Oracle's JDK, this creates a memory leak:
- 每个
Thread
都有一个专用字段threadLocals
,该字段实际上存储了线程局部值.
该映射中的每个 - 键 都是对
ThreadLocal
对象的弱引用,因此在该ThreadLocal
对象被垃圾回收后,其条目将从映射中删除. - 但是每个 value 是一个强引用,因此当一个值(直接或间接)指向作为其 key 的
ThreadLocal
对象时,该对象都不会只要线程存在,就可以对其进行垃圾收集或从地图中删除.
- Each
Thread
has a private fieldthreadLocals
, which actually stores the thread-local values. - Each key in this map is a weak reference to a
ThreadLocal
object, so after thatThreadLocal
object is garbage-collected, its entry is removed from the map. - But each value is a strong reference, so when a value (directly or indirectly) points to the
ThreadLocal
object that is its key, that object will neither be garbage-collected nor removed from the map as long as the thread lives.
在此示例中,强引用链如下所示:
In this example, the chain of strong references looks like this:
Thread
对象→threadLocals
映射→示例类的实例→示例类→静态ThreadLocal
字段→ThreadLocal
对象.
Thread
object → threadLocals
map → instance of example class → example class → static ThreadLocal
field → ThreadLocal
object.
(ClassLoader
在创建泄漏中并没有真正发挥作用,它只是由于以下附加引用链而使泄漏更糟:示例类→ClassLoader
→它已加载的所有类.更糟的是,在许多JVM实现中,尤其是在Java 7之前,这是因为类和ClassLoader
被直接分配到permgen中,并且根本没有被垃圾收集.)
(The ClassLoader
doesn't really play a role in creating the leak, it just makes the leak worse because of this additional reference chain: example class → ClassLoader
→ all the classes it has loaded. It was even worse in many JVM implementations, especially prior to Java 7, because classes and ClassLoader
s were allocated straight into permgen and were never garbage-collected at all.)
此模式的一种变体是为什么如果您频繁地重新部署恰巧使用ThreadLocal
且以某种方式指向自身的应用程序,那么应用程序容器(例如Tomcat)可以像筛子一样泄漏内存.发生这种情况的原因很多,通常很难调试和/或修复.
A variation on this pattern is why application containers (like Tomcat) can leak memory like a sieve if you frequently redeploy applications which happen to use ThreadLocal
s that in some way point back to themselves. This can happen for a number of subtle reasons and is often hard to debug and/or fix.
更新:由于很多人一直在要求它,所以这里是一些示例代码展示了这种行为的作用.
Update: Since lots of people keep asking for it, here's some example code that shows this behavior in action.
这篇关于如何在Java中创建内存泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!