我刚刚接受了一次采访,被要求用Java创建内存泄漏。
不用说,我觉得自己很傻,不知道如何开始创作。
什么样的例子?
我刚刚接受了一次采访,被要求用Java创建内存泄漏。
不用说,我觉得自己很傻,不知道如何开始创作。
什么样的例子?
当前回答
理论上你不能。Java内存模型阻止了这一点。但是,因为必须实现Java,所以可以使用一些警告。这取决于您可以使用什么:
如果可以使用本机,则可以分配以后不会放弃的内存。如果这是不可用的,那么Java有一个不为人知的小秘密。您可以请求一个不由GC管理的直接访问数组,因此可以很容易地用于造成内存泄漏。这由DirectByteBuffer提供(http://download.oracle.com/javase/1.5.0/docs/api/java/nio/ByteBuffer.html#allocateDirect(int))。如果不能使用其中任何一个,仍然可以通过欺骗GC来造成内存泄漏。JVM是使用一代垃圾收集来实现的。这意味着垃圾堆被划分为三个区域:年轻人、成年人和老年人。对象创建时从年轻区域开始。随着它被越来越多地使用,它逐渐发展到成人到老年人。最有可能到达接骨木区域的对象不会被垃圾收集。您无法确定对象是否泄漏,如果您请求停止并清理GC,它可能会清理它,但在很长一段时间内,它会泄漏。更多信息请访问(http://java.sun.com/docs/hotspot/gc1.4.2/faq.html)此外,类对象不需要是GC’ed。也许有办法做到这一点。
其他回答
在具有自己生命周期的类中随意使用非静态内部类。
在Java中,非静态内部类和匿名类对其外部类具有隐式引用。另一方面,静态内部类则不然。
下面是一个常见的Android内存泄漏示例,但这并不明显:
public class SampleActivity extends Activity {
private final Handler mLeakyHandler = new Handler() { // Non-static inner class, holds the reference to the SampleActivity outer class
@Override
public void handleMessage(Message msg) {
// ...
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Post a message and delay its execution for a long time.
mLeakyHandler.postDelayed(new Runnable() {//here, the anonymous inner class holds the reference to the SampleActivity class too
@Override
public void run() {
//....
}
}, SOME_TOME_TIME);
// Go back to the previous Activity.
finish();
}}
这将防止活动上下文被垃圾收集。
我在javax.swing.JPopupMenu中遇到了非常真实的内存泄漏。
我有一个GUI应用程序,它显示多个选项卡式文档。关闭文档后,如果在选项卡上的任何组件上使用了右键单击上下文菜单,它就会在内存中停留。这些菜单在选项卡之间共享,结果是,在调用popupMenu.show(component invoker,int x,int y)后,组件会作为菜单的“调用程序”静静地存在,直到下一次更改或被setInvoker(null)清除。间接地,调用者引用持久化了整个文档以及与之相关的所有内容。
值得注意的是,菜单只能以这种方式保存对旧组件的一个引用,因此这种内存泄漏不会在没有绑定的情况下增长。
我曾经有过一次关于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)需要大约两天的时间才能到达。。。
要做的一件简单的事情是使用带有不正确(或不存在)hashCode()或equals()的HashSet,然后继续添加“重复项”。而不是像应该的那样忽略重复项,集合只会增长,您将无法删除它们。
如果你想让这些坏键/元素到处乱动,你可以使用一个静态字段,比如
class BadKey {
// no hashCode or equals();
public final String key;
public BadKey(String key) { this.key = key; }
}
Map map = System.getProperties();
map.put(new BadKey("key"), "value"); // Memory leak even if your threads die.
每个人都会忘记本机代码路径。以下是泄漏的简单公式:
声明本机方法。在本机方法中,调用malloc。不要打免费电话。调用本机方法。
记住,本机代码中的内存分配来自JVM堆。