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

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

什么样的例子?


当前回答

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

其他回答

要做的一件简单的事情是使用带有不正确(或不存在)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.

如果最大堆大小为X.Y1….Yn实例数

因此,总内存=每个实例的实例数X字节。如果X1……Xn是每个实例的字节数,则总内存(M)=Y1*X1++Yn*Xn。因此,如果M>X,它将超过堆空间。

以下可能是代码中的问题

使用更多实例变量,然后使用局部变量。每次都创建实例,而不是共享对象。未按需创建对象。操作完成后使对象引用为空。再次,在程序中需要时重新创建。

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

我觉得有趣的是,没有人使用内部类示例。如果您有内部类;它固有地维护对包含类的引用。当然,从技术上讲,这不是内存泄漏,因为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假设它将永远存在,并且如果代码中无法访问它,它实际上永远不会尝试清理它。但这完全未经证实。

不终止的线程(比如在其运行方法中无限期休眠)。即使我们丢失了对它的引用,它也不会被垃圾收集。您可以添加字段以使线程对象变大。

目前排名靠前的答案列出了更多的技巧,但这些似乎是多余的。