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

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

什么样的例子?


当前回答

内存泄漏的情况有很多种。我遇到了一个,它暴露了一个不应该在其他地方暴露和使用的地图。

public class ServiceFactory {

    private Map<String, Service> services;

    private static ServiceFactory singleton;

    private ServiceFactory() {
        services = new HashMap<String, Service>();
    }

    public static synchronized ServiceFactory getDefault() {

        if (singleton == null) {
            singleton = new ServiceFactory();
        }
        return singleton;
    }

    public void addService(String name, Service serv) {
        services.put(name, serv);
    }

    public void removeService(String name) {
        services.remove(name);
    }

    public Service getService(String name, Service serv) {
        return services.get(name);
    }

    // The problematic API, which exposes the map.
    // and user can do quite a lot of thing from this API.
    // for example, create service reference and forget to dispose or set it null
    // in all this is a dangerous API, and should not expose
    public Map<String, Service> getAllServices() {
        return services;
    }

}

// Resource class is a heavy class
class Service {

}

其他回答

您可以通过在类的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());
        }
    }
}

就像这样!

public static void main(String[] args) {
    List<Object> objects = new ArrayList<>();
    while(true) {
        objects.add(new Object());
    }
}

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

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

对前面的答案有一点改进(为了更快地生成内存泄漏),就是使用从大型XML文件加载的DOM文档实例。

我认为还没有人说过这一点:你可以通过重写finalize()方法来复活一个对象,这样finalize)就可以在某个地方存储对它的引用。垃圾回收器只会在对象上调用一次,因此在此之后,对象将永远不会被销毁。