我不知道如何回答这个问题。相反,我告诉他们我没有在 Web应用程序中看到任何可能导致内存泄漏的实际代码/情况。我还告诉他,如果创建的对象太多而且这些对象超出范围, GC 将负责回收内存。
我的问题是 (1)我的回答是否足够好? (2)您能否在Web和/或非Web环境中给我一个Java内存泄漏的实际示例?
由于
答案 0 :(得分:2)
好主题!
您需要首先监控Java内存消耗。
最简单的方法是使用每个JVM附带的jstat
实用程序。
jstat -gcutil <process_id> <timeout>
它将报告每一代(Young,Eldery和Old)的内存消耗和垃圾收集时间(Young和Full)。
一旦发现Full Garbage Collection执行过于频繁并且花费太多时间,您就可以认为应用程序正在泄漏内存。
然后,您需要使用jmap
实用程序创建内存转储:
jmap -dump:live,format=b,file=heap.bin <process_id>
然后,您需要使用Memory Analyzer,Eclipse Memory Analyzer(MAT)分析heap.bin文件。
MAT将分析内存并为您提供有关内存泄漏的可疑信息。
答案 1 :(得分:0)
内存泄漏,在任何情况下,您继续保持已分配的内存,不再需要并且不再打算使用。
考虑以下示例:
public class LeakMemory {
private static final List<String> LEAK = new ArrayList<>();
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("What is your name? ");
while (in.hasNext()) {
name = in.next();
System.out.println("Hi " + name);
LEAK.add(name);
}
}
}
LEAK列表在每次迭代中都会增长,并且没有办法将其释放,但它从未使用过。这是泄密。
答案 2 :(得分:0)
通过memory leak的正常定义,由于垃圾收集,Java没有它们。但是,如果我们将定义稍微扩展为“程序不再需要的对象,但不是垃圾可收集的”,那么有两种情况我可以想到可能出现这种“泄漏”的地方。
场景1:记录所创建的类的所有对象
这个例子具有人造味道,常常在练习的背景下看到。假设我们想要存储所创建的某个类的每个实例。这可以通过静态集合来实现:
public class RecordMe {
private static final List<RecordMe> created = new ArrayList<RecordMe>();
...
private final int someValue;
private RecordMe(final int someValue) {
this.someValue = someValue;
}
public static RecordMe of(final int someValue) {
RecordMe me = new RecordMe(someValue);
created.add(me);
return me;
}
public static List<RecordMe> instances() {
return Collections.unmodifiableList(created);
}
}
只要创建RecordMe
的实例,它就永远不会被垃圾收集,因为它将始终通过静态列表引用。
修复方法是在创建RecordMe
的新实例或使用List<
WeakReference<RecordMe>
>
之前检查列表(并不时清理此列表)。
场景2:内部课程泄漏
正如我们所知,非staitc内部类拥有对其创建对象的隐式引用。让我们来看一个极端的例子。
public class MemoryTest {
// data has a size of a little over 512 MB.
private final byte[] data = new byte[1024 * 1024 * 512];
private final Field field;
public class Field {
}
public MemoryTest() {
this.field = new Field();
}
public Field getField() {
return this.field;
}
public static void main(String... args) {
MemoryTest test = new MemoryTest();
Field fieldOne = test.getField();
test = null;
test = new MemoryTest();
}
}
如果我们使用java -Xmx800m MemoryTest
执行此代码,则会抛出OutOfMemoryException
。这种尺寸的例子在现实中是不现实的,但是在较小的尺寸和足够的实例中,这也可能导致问题。举例来说,Java的HashMap
- 实现。方法keySet()
返回非静态内部类的实例。只要有一个实例保存那些内部类,HashMap
就不能被垃圾收集。