在Java中导致内存泄漏的最简单方法?

Pau*_*zie 34 java memory-leaks

可能重复:
使用Java创建内存泄漏

什么是导致java内存泄漏的最简单方法?

fdr*_*ger 30

你不能真正在Java中"泄漏内存",除非你:

  • 实习生的字符串
  • 生成类
  • 泄漏由jni调用的本机代码中的内存
  • 在一些被遗忘或模糊的地方保留对你不想要的东西的引用.

我认为你对最后一案感兴趣.常见的情况是:

  • 听众,特别是内部类
  • 缓存.

一个很好的例子是:

  • 建立一个可以无限数量的模态窗口的Swing gui;
  • 让模态窗口在初始化期间执行类似的操作:
    StaticGuiHelper.getMainApplicationFrame().getOneOfTheButtons().addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e){
         // do nothing...
      }
    })
    

注册的操作什么都不做,但它会导致模态窗口永远停留在内存中,即使在关闭之后也会导致泄漏 - 因为侦听器永远不会被注册,并且每个匿名内部类对象都拥有对其外部对象的引用(不可见) .更重要的是 - 从模态窗口引用的任何对象都有可能泄漏.

这就是为什么像EventBus这样的库默认使用弱引用的原因.

除了听众之外,其他典型的例子都是缓存,但我想不出一个很好的例子.

  • Interned字符串不是真正的内存泄漏,它们也可以被垃圾收集.问题只在于它们(在通常的实现中)位于特殊的存储区域(PermGen)中,它比存储器的其余部分小,因此更容易填满. (4认同)

yan*_*kee 15

"当计算机程序消耗内存但无法将其释放回操作系统时,会发生计算机科学(或泄漏,在此上下文中)的内存泄漏." (维基百科)

简单的答案是:你做不到.Java执行自动内存管理,并将释放您不需要的资源.你不能阻止这种情况发生.它总是能够释放资源.在具有手动内存管理的程序中,这是不同的.你可以使用malloc()在C中获得一些内存.要释放内存,您需要malloc返回的指针并在其上调用free().但是如果你不再使用指针(覆盖或超过生命周期),那么很遗憾你无法释放这个内存,因此你有内存泄漏.

到目前为止,所有其他答案都在我的定义中并非真正的内存泄漏.它们都旨在快速填充无意义的内存.但是在任何时候你仍然可以取消引用你创建的对象,从而释放内存 - >没有泄漏.acconrad的答案非常接近,但我不得不承认,因为他的解决方案实际上是通过强制它在无限循环中"崩溃"垃圾收集器.

答案很长:您可以通过使用JNI编写Java库来获取内存泄漏,JNI可能具有手动内存管理功能,因此存在内存泄漏.如果你调用这个库,你的java进程将泄漏内存.或者,您可能在JVM中有错误,因此JVM会丢失内存.JVM中可能存在bug,甚至可能有一些已知的bug,因为垃圾收集不是那么简单,但它仍然是一个bug.按设计这是不可能的.你可能会要求一些受这种bug影响的java代码.对不起,我不知道一个,无论如何它在下一个Java版本中可能不再是一个bug.

  • "但在任何时候你仍然可以取消引用你创建的对象,从而释放内存".我不同意.类实现者可以隐藏来自外部世界的对象句柄. (2认同)

acc*_*rad 11

这是一个简单的例子

public class Finalizer {
    @Override
    protected void finalize() throws Throwable {
        while (true) {
            Thread.yield();
        }
    }

    public static void main(String[] args) {
        while (true) {
            for (int i = 0; i < 100000; i++) {
                Finalizer f = new Finalizer();
            }

            System.out.println("" + Runtime.getRuntime().freeMemory() + " bytes free!");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @TheBlueNotebook他覆盖的finalize方法是Java通常在为一个Object释放内存时调用的方法.在他的主要方法中,他创建了100K的终结器,然后告诉JVM释放所有内存.JVM礼貌地执行此操作并在实际释放内存之前调用finalize.它调用的finalize方法永远产生,因此对象永远不会被删除,但主循环继续,从而创建另一个永远不会删除的100K对象,然后是另一个,然后另一个... (3认同)
  • 你能解释一下你是如何实现这个例子中的内存泄漏的吗? (2认同)

Boz*_*zho 9

public static List<byte[]> list = new ArrayList<byte[]>();
Run Code Online (Sandbox Code Playgroud)

然后添加(大)数组而不删除它们.在某些时候,你会在没有怀疑的情况下耗尽内存.(您可以对任何对象执行此操作,但使用大型完整阵列可以更快地耗尽内存)

在Java中,如果取消引用对象(它超出范围),则会对其进行垃圾回收.所以你必须持有它的引用才能产生内存问题.

  • @mikerobi - 内存泄漏就是当你"占用"一些内存而不清理它(并且不使用它)时.但是,如果取消引用该对象,它将被垃圾收集. (6认同)