我刚刚接受了一次采访,被要求用Java创建内存泄漏。

不用说,我觉得自己很傻,不知道如何开始创作。

什么样的例子?


当前回答


import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class Main {
    public static void main(String args[]) {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            ((Unsafe) f.get(null)).allocateMemory(2000000000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

其他回答

GUI代码中的一个常见示例是创建小部件/组件并向某个静态/应用程序范围的对象添加侦听器,然后在小部件被破坏时不删除侦听器。不仅会出现内存泄漏,而且性能也会受到影响,因为无论你听什么都会引发事件,所有的老听众都会被调用。

Java内存泄漏的一个例子是当忘记调用ResultSets close方法时导致的MySQL内存泄漏错误。例如:

while(true) {
    ResultSet rs = database.select(query);
    ...
    // going to next step of loop and leaving resultset without calling rs.close();
}

答案完全取决于面试官认为他们在问什么。

在实践中是否可能造成Java泄漏?当然是这样,其他答案中有很多例子。

但有很多元问题可能被问到了?

理论上“完美”的Java实现是否容易泄漏?候选人是否理解理论与现实之间的区别?应聘者是否了解垃圾收集的工作原理?或者垃圾收集在理想情况下应该如何工作?他们知道他们可以通过本地接口调用其他语言吗?他们知道用其他语言泄露内存吗?应聘者是否知道什么是内存管理,以及Java的幕后情况?

我把你的元问题理解为“在这种面试情况下我可以用什么答案”。因此,我将重点关注面试技巧,而不是Java。我相信,你更可能重复在面试中不知道问题答案的情况,而不是你需要知道如何使Java泄漏。所以,希望这会有所帮助。

你可以培养的面试最重要的技能之一是学会积极倾听问题,并与面试官合作以提取他们的意图。这不仅可以让你以他们想要的方式回答他们的问题,还表明你有一些重要的沟通技巧。当要在许多同样有才华的开发人员之间做出选择时,我会雇佣一个在他们每次回应之前都能倾听、思考和理解的人。

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

应用程序创建一个长时间运行的线程(或者使用线程池更快地泄漏)。线程通过(可选的自定义)ClassLoader加载类。该类分配一大块内存(例如新字节[10000000]),在静态字段中存储对它的强引用,然后在ThreadLocal中存储对自身的引用。分配额外的内存是可选的(泄漏类实例就足够了),但这会使泄漏工作得更快。应用程序清除对自定义类或从中加载该类的ClassLoader的所有引用。重复

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

每个线程都有一个私有字段threadLocals,它实际上存储线程本地值。此映射中的每个键都是对ThreadLocal对象的弱引用,因此在ThreadLocal对象被垃圾收集后,其条目将从映射中删除。但每个值都是一个强引用,因此当一个值(直接或间接)指向作为其键的ThreadLocal对象时,只要线程存在,该对象既不会被垃圾收集,也不会从映射中删除。

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

线程对象→ threadLocals映射→ 示例类的实例→ 示例类→ 静态ThreadLocal字段→ ThreadLocal对象。

(ClassLoader在创建泄漏时并没有真正发挥作用,它只是因为这个额外的引用链而使泄漏变得更糟:example类→ 类加载器→ 它加载的所有类。在许多JVM实现中,尤其是在Java7之前,情况更糟,因为类和ClassLoader被直接分配到permagen中,根本不会被垃圾收集。)

这种模式的一个变体是,如果您经常重新部署碰巧使用ThreadLocal的应用程序,而这些应用程序在某种程度上指向自己,那么应用程序容器(如Tomcat)会像筛子一样泄漏内存。这种情况可能有许多微妙的原因,并且通常很难调试和/或修复。

更新:由于很多人一直在要求它,这里有一些示例代码显示了这种行为。

每个人都会忘记本机代码路径。以下是泄漏的简单公式:

声明本机方法。在本机方法中,调用malloc。不要打免费电话。调用本机方法。

记住,本机代码中的内存分配来自JVM堆。