如何在Java中创建内存泄漏? [英] How to create a memory leak in Java?

查看:87
本文介绍了如何在Java中创建内存泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚接受采访,并被要求使用Java创建 内存泄漏 .
不用说,我对如何开始创建它一无所知.

一个例子是什么?

解决方案

这是在纯Java中创建真正的内存泄漏(运行代码无法访问但仍存储在内存中的对象)的好方法:

  1. 应用程序将创建一个长期运行的线程(或使用线程池以更快地泄漏).
  2. 线程通过(可选)ClassLoader加载类.
  3. 该类分配大量内存(例如new byte[1000000]),在静态字段中存储对它的强引用,然后在ThreadLocal中存储对自身的引用.分配额外的内存是可选的(泄漏类实例就足够了),但这将使泄漏工作快得多.
  4. 应用程序清除对自定义类或从其加载的ClassLoader的所有引用.
  5. 重复.

由于在Oracle的JDK中实现ThreadLocal的方式,这会导致内存泄漏:

  • 每个Thread都有一个专用字段threadLocals,该字段实际上存储了线程局部值.
  • 该地图中的每个
  • 都是对ThreadLocal对象的弱引用,因此在该ThreadLocal对象被垃圾回收之后,其条目将从地图中删除.
  • 但是每个 value 是一个强引用,因此当一个值(直接或间接)指向作为其 key ThreadLocal对象时,该对象都不会只要线程存在,就可以对其进行垃圾收集或从地图中删除.

在此示例中,强引用链如下所示:

Thread对象→threadLocals映射→示例类的实例→示例类→静态ThreadLocal字段→ThreadLocal对象.

(ClassLoader并没有真正在创建泄漏中起作用,它只是由于以下附加引用链而使泄漏更糟:示例类→ClassLoader→它已加载的所有类.更糟的是,在许多JVM实现中,尤其是在Java 7之前,这是因为类和ClassLoader直接分配到permgen中,并且根本没有被垃圾收集.

此模式的一个变体是为什么如果您频繁地重新部署恰巧使用ThreadLocal且以某种方式指向自身的应用程序,则应用程序容器(例如Tomcat)可以像筛子一样泄漏内存.发生这种情况的原因很多,通常很难调试和/或修复.

更新:由于很多人一直在要求它,所以这里是一些示例代码展示了这种行为的作用.

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.

What would an example be?

解决方案

Here's a good way to create a true memory leak (objects inaccessible by running code but still stored in memory) in pure Java:

  1. The application creates a long-running thread (or use a thread pool to leak even faster).
  2. The thread loads a class via an (optionally custom) ClassLoader.
  3. 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 a ThreadLocal. Allocating the extra memory is optional (leaking the class instance is enough), but it will make the leak work that much faster.
  4. The application clears all references to the custom class or the ClassLoader it was loaded from.
  5. Repeat.

Due to the way ThreadLocal is implemented in Oracle's JDK, this creates a memory leak:

  • Each Thread has a private field threadLocals, which actually stores the thread-local values.
  • Each key in this map is a weak reference to a ThreadLocal object, so after that ThreadLocal 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 object → threadLocals map → instance of example class → example class → static ThreadLocal field → ThreadLocal object.

(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 ClassLoaders were allocated straight into permgen and were never garbage-collected at all.)

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 ThreadLocals 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆