什么是内存泄漏?
内存泄漏(Memory Leak),是指程序在申请内存之后,无法释放已申请的内存空间。内存泄漏会导致内存空间的浪费,大量的内存泄漏会导致程序内存溢出(Out Of Memory)。
引起内存泄漏的原因
Java虽然有GC管理内存的回收,但是同样会面临GC无法回收的情况,造成内存泄漏。通常有以下几种产生原因:
静态集合类引起的内存泄漏
静态集合在使用时容易出现内存泄漏,由于静态变量的生命周期和应用程序一致,所以程序关闭的时候集合变量占用的空间才会被释放,它们所引用的对象也一直被引用着,无法被GC回收。
package javauser;
import java.util.ArrayList;
import java.util.List;
public class MemoryLeak {
static List<Object> list = new ArrayList<>();
public static void main(String[] args) {
while (true) {
MemoryUse m = new MemoryUse();
list.add(m);
m = null;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MemoryUse {
}
执行GC前,
执行GC后,
可以看出,在执行GC后,javauser.MemoryUse的实例并没有减少,说明GC并没有进行回收。使用list = null
,将可以避免这种情况。
未关闭的流引起的内存泄漏
在连接数据库池、网络或者读取文件时,没有关闭连接会造成内存泄漏。GC不会主动回收这些连接,所以需要使用close()
方法来主动关闭。
单例模式引起的内存泄漏
package javauser;
public class SingleMemoryLeak {
private M m;
private static SingleMemoryLeak singleMemoryLeak = new SingleMemoryLeak();
private SingleMemoryLeak() {}
public static SingleMemoryLeak getInstance() {
return singleMemoryLeak;
}
public void setM(M m) {
this.m = m;
}
}
class M {
public M() {
SingleMemoryLeak.getInstance().setM(this);
}
}
SingleMemoryLeak实现了单例模式,SingleMemoryLeak持有M实例的引用,这个实例将不能被回收。