Java中常见的内存泄露出现的方式

1:根本原因

  长生命周期的对象持有短生命周期对象的引用会导致内存泄露。这是因为虽然短生命周期的对象已经没有了外部引用,可以被i释放了,但是被长生命周期的对象持有,不能释放。

2:具体情况

2.1:集合类引起内存泄露

  比如:集合类中存放指定对象,但是对象引用已经失效,由于对象存放在集合中,所以无法释放该对象的内存。

ArrayList <Object> al = new ArrayList(10);
for(int i=0;i<10;i++){
  Object obj = new Object();
  al.add(obj);
  obj = null;  
}

2.2:监听器

在java 编程中,我们都需要和监听器打交道,通常一个应用当中会用到很多监听器,我们会调用一个控件的诸如addXXXListener()等方法来增加监听器,但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了内存泄漏的机会

2.3:各种连接

比如数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC 回收的。对于Resultset 和Statement 对象可以不进行显式回收,但Connection 一定要显式回收,因为Connection 在任何时候都无法自动回收,而Connection一旦回收,Resultset 和Statement 对象就会立即为NULL。但是如果使用连接池,情况就不一样了,除了要显式地关闭连接,还必须显式地关闭Resultset Statement 对象(关闭其中一个,另外一个也会关闭),否则就会造成大量的Statement 对象无法释放,从而引起内存泄漏。这种情况下一般都会在try里面去的连接,在finally里面释放连接。

2.4:单例模式

如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露

不正确使用单例模式是引起内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露,考虑下面的例子:

class A{
public A(){
B.getInstance().setA(this);
}
....
}
//B类采用单例模式
class B{
private A a;
private static B instance=new B();
public B(){}
public static B getInstance(){
return instance;
}
public void setA(A a){
this.a=a;
}
//getter...
}

A类的对象将无法被GC回收!!

猜你喜欢

转载自www.cnblogs.com/dazhu123/p/12755714.html