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

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

什么样的例子?


当前回答

这很简单:

Object[] o = new Object[]{};
while(true) {
    o = new Object[]{o};
}

其他回答

Java1.6中的String.substring方法会造成内存泄漏。这篇博文解释了这一点:

SubString方法在Java中的工作原理-JDK1.7中修复了内存泄漏

您可以尝试使用while循环使许多缓冲的读取器尝试同时打开同一个文件,条件决不为false。最上面的樱桃是这些永远不会关闭。

我觉得有趣的是,没有人使用内部类示例。如果您有内部类;它固有地维护对包含类的引用。当然,从技术上讲,这不是内存泄漏,因为Java最终会清理掉它;但这会导致类停留的时间比预期的长。

public class Example1 {
  public Example2 getNewExample2() {
    return this.new Example2();
  }
  public class Example2 {
    public Example2() {}
  }
}

现在,如果您调用Example1并得到一个Example2丢弃Example1,那么您本质上仍然有一个到Example1对象的链接。

public class Referencer {
  public static Example2 GetAnExample2() {
    Example1 ex = new Example1();
    return ex.getNewExample2();
  }

  public static void main(String[] args) {
    Example2 ex = Referencer.GetAnExample2();
    // As long as ex is reachable; Example1 will always remain in memory.
  }
}

我还听到一个传言,如果你有一个变量存在的时间超过了一个特定的时间;Java假设它将永远存在,并且如果代码中无法访问它,它实际上永远不会尝试清理它。但这完全未经证实。

我认为,一个有效的例子可能是在线程集中的环境中使用ThreadLocal变量。

例如,使用Servlet中的ThreadLocal变量与其他web组件通信,让容器创建线程,并在池中维护空闲线程。ThreadLocal变量如果没有正确清理,将一直存在,直到同一个web组件覆盖它们的值。

当然,一旦确定,问题很容易解决。

保存对象引用的静态字段(尤其是最终字段)

class MemorableClass {
    static final ArrayList list = new ArrayList(100);
}

(未关闭)开放流(文件、网络等)

try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStackTrace();
}

未封闭的连接

try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStackTrace();
}

JVM垃圾收集器无法访问的区域,例如通过本机方法分配的内存。

在web应用程序中,某些对象存储在应用程序范围中,直到应用程序被显式停止或删除。

getServletContext().setAttribute("SOME_MAP", map);

不正确或不适当的JVM选项,例如IBM JDK上的noclassgc选项,它阻止未使用的类垃圾收集

请参阅IBM JDK设置。