导致java内存泄漏的最简单方法是什么?
答案 0 :(得分:29)
除非你:
,否则你无法在Java中“泄漏内存”我认为你对最后一案感兴趣。常见的情况是:
一个很好的例子是:
StaticGuiHelper.getMainApplicationFrame().getOneOfTheButtons().addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
// do nothing...
}
})
注册的操作什么都不做,但它会导致模态窗口永远停留在内存中,即使在关闭之后也会导致泄漏 - 因为侦听器永远不会被注册,并且每个匿名内部类对象都拥有一个引用(不可见)它的外在物体。更重要的是 - 从模态窗口引用的任何对象都有可能泄漏。
这就是为什么像EventBus这样的库默认使用弱引用。
除了听众之外,其他典型的例子都是缓存,但我想不出一个很好的例子。
答案 1 :(得分:15)
“当计算机程序消耗内存但无法将其释放回操作系统时,会发生计算机科学(或泄漏,在此上下文中)的内存泄漏。” (维基百科)
简单的答案是:你做不到。 Java执行自动内存管理,并将释放您不需要的资源。你不能阻止这种情况发生。它总是能够释放资源。在具有手动内存管理的程序中,这是不同的。你可以使用malloc()在C中获得一些内存。要释放内存,您需要malloc返回的指针并在其上调用free()。但是如果你不再使用指针(覆盖或超过生命周期),那么很遗憾你无法释放这些内存,从而导致内存泄漏。
到目前为止,所有其他答案都在我的定义中并非真正的内存泄漏。它们都旨在快速填充无意义的内存。但是在任何时候你仍然可以取消引用你创建的对象,从而释放内存 - >没有泄漏。 acconrad的答案非常接近,但我不得不承认,因为他的解决方案实际上只是通过强制它在无限循环中“崩溃”垃圾收集器。
答案很长:您可以通过使用JNI编写Java库来获取内存泄漏,JNI可以进行手动内存管理,从而导致内存泄漏。如果你调用这个库,你的java进程将泄漏内存。或者,您可能在JVM中有错误,因此JVM会丢失内存。 JVM中可能存在bug,甚至可能有一些已知的bug,因为垃圾收集不是那么简单,但它仍然是一个bug。按设计这是不可能的。你可能会要求一些受这种bug影响的java代码。对不起,我不知道一个,不管怎样,在下一个Java版本中它可能不再是一个bug。
答案 2 :(得分: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!");
}
}
}
答案 3 :(得分:8)
public static List<byte[]> list = new ArrayList<byte[]>();
然后添加(大)数组而不删除它们。在某些时候,你会在没有怀疑的情况下耗尽内存。 (您可以对任何对象执行此操作,但使用大型完整阵列可以更快地耗尽内存)
在Java中,如果取消引用对象(它超出范围),则会对其进行垃圾回收。因此,您必须持有对它的引用才能出现内存问题。
答案 4 :(得分:3)
因为始终存在对集合的引用以及拥有集合的对象的实例,垃圾收集器将永远不会清理该内存,从而导致“泄漏”。
答案 5 :(得分:3)
从我在最多投票的答案中读到的内容,你很可能会要求类似C的内存泄漏。好吧,因为有garbagge集合,你不能分配一个对象,松散它的所有引用并使它仍然占用内存 - 这将是严重的JVM错误。
另一方面,你可能碰巧泄漏线程 - 这当然会导致这种状态,因为你会有一些线程运行它对对象的引用,你可能会松开线程的引用。您仍然可以通过API获取Thread引用 - http://www.exampledepot.com/egs/java.lang/ListThreads.html
答案 6 :(得分:1)
如果使用的话,下面非常人为的Box
类会泄漏内存。对put
进入此类的对象最终(在另一次调用put
之后是准确的...如果相同的对象没有重新put
进入它。)外部无法访问世界。它们不能通过这个类解除引用,但是这个类确保它们不能被收集。这是一个真正的泄漏。我知道这是非常人为的,但类似的情况可能是偶然的。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Stack;
public class Box <E> {
private final Collection<Box<?>> createdBoxes = new ArrayList<Box<?>>();
private final Stack<E> stack = new Stack<E>();
public Box () {
createdBoxes.add(this);
}
public void put (E e) {
stack.push(e);
}
public E get () {
if (stack.isEmpty()) {
return null;
}
return stack.peek();
}
}
答案 7 :(得分:0)
试试这个简单的课程:
public class Memory {
private Map<String, List<Object>> dontGarbageMe = new HashMap<String, List<Object>>();
public Memory() {
dontGarbageMe.put("map", new ArrayList<Object>());
}
public void useMemInMB(long size) {
System.out.println("Before=" + getFreeMemInMB() + " MB");
long before = getFreeMemInMB();
while ((before - getFreeMemInMB()) < size) {
dontGarbageMe.get("map").add("aaaaaaaaaaaaaaaaaaaaaa");
}
dontGarbageMe.put("map", null);
System.out.println("After=" + getFreeMemInMB() + " MB");
}
private long getFreeMemInMB() {
return Runtime.getRuntime().freeMemory() / (1024 * 1024);
}
public static void main(String[] args) {
Memory m = new Memory();
m.useMemInMB(15); // put here apropriate huge value
}
}
答案 8 :(得分:0)
似乎大多数答案都不是C风格的内存泄漏。
我以为我会添加一个库类的示例,其中包含一个会导致内存不足异常的错误。同样,它不是真正的内存泄漏,而是一个你不会期望的内存不足的例子。
public class Scratch {
public static void main(String[] args) throws Exception {
long lastOut = System.currentTimeMillis();
File file = new File("deleteme.txt");
ObjectOutputStream out;
try {
out = new ObjectOutputStream(
new FileOutputStream("deleteme.txt"));
while (true) {
out.writeUnshared(new LittleObject());
if ((System.currentTimeMillis() - lastOut) > 2000) {
lastOut = System.currentTimeMillis();
System.out.println("Size " + file.length());
// out.reset();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class LittleObject implements Serializable {
int x = 0;
}
您可以在
找到原始代码和错误说明