我刚刚接受了一次采访,被要求用Java创建内存泄漏。
不用说,我觉得自己很傻,不知道如何开始创作。
什么样的例子?
我刚刚接受了一次采访,被要求用Java创建内存泄漏。
不用说,我觉得自己很傻,不知道如何开始创作。
什么样的例子?
当前回答
一些建议:
在servlet容器中使用commons日志记录(可能有点挑衅)在servlet容器中启动线程,不要从其运行方法返回在servlet容器中加载动画GIF图像(这将启动一个动画线程)
通过重新部署应用程序,可以“改善”上述效果;)
我最近偶然发现:
调用“newjava.util.zip。充气器();”而不调用“充气器.end()”
阅读http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5072161并将问题联系起来进行深入讨论。
其他回答
我曾经有过一次关于PermGen和XML解析的“内存泄漏”。我们使用的XML解析器(我记不清是哪一个)对标记名执行String.intern(),以加快比较速度。我们的一位客户有一个好主意,不将数据值存储在XML属性或文本中,而是将其存储为标记名,因此我们有了这样一个文档:
<data>
<1>bla</1>
<2>foo</>
...
</data>
事实上,他们没有使用数字,而是使用更长的文本ID(约20个字符),这些ID是唯一的,每天的使用率为1000万至1000万。这使得每天有200 MB的垃圾,而这些垃圾再也不需要了,也永远不会被GCed(因为它在PermGen中)。我们将permagen设置为512MB,因此内存不足异常(OOME)需要大约两天的时间才能到达。。。
我认为,一个有效的例子可能是在线程集中的环境中使用ThreadLocal变量。
例如,使用Servlet中的ThreadLocal变量与其他web组件通信,让容器创建线程,并在池中维护空闲线程。ThreadLocal变量如果没有正确清理,将一直存在,直到同一个web组件覆盖它们的值。
当然,一旦确定,问题很容易解决。
这是一个简单/险恶的http://wiki.eclipse.org/Performance_Bloopers#String.substring.28.29.
public class StringLeaker
{
private final String muchSmallerString;
public StringLeaker()
{
// Imagine the whole Declaration of Independence here
String veryLongString = "We hold these truths to be self-evident...";
// The substring here maintains a reference to the internal char[]
// representation of the original string.
this.muchSmallerString = veryLongString.substring(0, 1);
}
}
因为子字符串指的是原始字符串的内部表示,所以原始字符串会保留在内存中。因此,只要你有一个StringLeaker在玩,你的记忆中也有整个原始字符串,即使你可能认为你只是在保存一个字符串。
避免存储对原始字符串的不需要的引用的方法如下:
...
this.muchSmallerString = new String(veryLongString.substring(0, 1));
...
为了增加坏处,您还可以.intern()子字符串:
...
this.muchSmallerString = veryLongString.substring(0, 1).intern();
...
这样做将在内存中保留原始的长字符串和派生的子字符串,即使在StringLeaker实例被丢弃之后也是如此。
这很简单:
Object[] o = new Object[]{};
while(true) {
o = new Object[]{o};
}
您可以通过在类的finalize方法中创建类的新实例来创建移动内存泄漏。如果终结器创建多个实例,则会获得加分。下面是一个简单的程序,它可以在几秒钟到几分钟内泄漏整个堆,具体取决于堆的大小:
class Leakee {
public void check() {
if (depth > 2) {
Leaker.done();
}
}
private int depth;
public Leakee(int d) {
depth = d;
}
protected void finalize() {
new Leakee(depth + 1).check();
new Leakee(depth + 1).check();
}
}
public class Leaker {
private static boolean makeMore = true;
public static void done() {
makeMore = false;
}
public static void main(String[] args) throws InterruptedException {
// make a bunch of them until the garbage collector gets active
while (makeMore) {
new Leakee(0).check();
}
// sit back and watch the finalizers chew through memory
while (true) {
Thread.sleep(1000);
System.out.println("memory=" +
Runtime.getRuntime().freeMemory() + " / " +
Runtime.getRuntime().totalMemory());
}
}
}