java内存泄露总结(参考了一些网上的知识)

JAVA内存泄露
李海燕 2016/7/18
1.概念
 内存泄露(Memory Leak):程序申请内存后,无法释放申请的内存空间,内存泄露最终会导致溢出;
 内存溢出:欲申请的内存超出了系统可以给出,抛出内存溢出异常;

2.如何检测
2.1 使用内存映像分析工具(Eclipse Memory Analyzer)对Dump出来的堆转储快照进行分析,确认内存中的对象是不是必要的,如果是必要的那就是发生了溢出,不必要的就是内存泄露了;
2.2 使用jps获取线程ID,然后打开Jconsole id;观察内存使用情况即可;

3.溢出原因
根本原因:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。

说明:对于数组的操作,堆和栈的操作要慎重的考虑泄露问题(出栈的时候没有清理掉最后一个元素即没有对最后一个元素置空);

4.举例说明

4.1 使用HashMap不当
说明:HashMap里面添加元素,如果key没有实现hashCode()和equals()方法,这样相同的对象会重复加入HashMap中,GC也不会回收的;
比如代码中出现:while(true){hashmap.put(new Key(“kk”),”ll”)}那么一直执行,最后会导致OutOfMemory异常;

4.2 大量使用String
说明:比如需要拼接字符串时候,如果使用String类,那就会生成大量的中间对象,放置在常量池中,GC主要针对堆进行回收,运行时常量池属于永久代,永久代中回收主要针对:常量池的回收和类型的卸载比较严格。容易造成一段时间的内存泄露。
4.3 监听器
在java 编程中,我们都需要和监听器打交道,通常一个应用当中会用到很多监听器,我们会调用一个控件的诸如addXXXListener()等方法来增加监听器,但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了内存泄漏的机会。
比如Java中观察者模式实现是通过继承Observable类的对象:调用setChanged()方法和notifyObservers()通知监听对象执行update()方法;同时监听对象必须实现Observer接口的update(Observable obserale,Object args)方法,因此监听器构造方法(this引用逃逸)必须指定或者提供一个方法指定Observable对象,然后调用给对象的addObserver(this)方法,就OK了;
4.4 各种连接
如数据库连接(dataSource.getConnection())、网络连接(socket)和IO连接必须显示的关闭连接,否则GC不会回收这些对象的,一般在try里面去连接,最后在finally里面close();
4.4 内部类引用
内部类的引用是比较容易遗忘的一种,而且一旦没释放可能导致一系列的后继类对象没有释放。此外程序员还要小心外部模块不经意的引用,例如程序员A 负责A 模块,调用了B 模块的一个方法如:
                public void registerMsg(Object b);
   这种调用就要非常小心了,传入了一个对象,很可能模块B就保持了对该对象的引用,这时候就需要注意模块B 是否提供相应的操作去除引用。
4.5 单例模式
比如一个单例模式内部引用了一个对象,我们知道单例模式的话以静态变量形式存在整个生命周期里面,所以会一直持有对那个对象的引用,假想那个对象是一个很大的数组或者集合,本来那个对象生命周期到了,可却因为单例模式的引用导致不能回收;
观察假如我们在一个Activity A中使用了Util类:Util.getInstance(this),那么这个A对象一定不能释放;
public class Util {
private Context mContext;
private static Util instance=null;
private Util(Context context){
this.mContext = context;
}
public static Util getInstance(Context context){
if(instace==null){
synchronized(Util.class){
if(instance==null)instance=new Util(context);
}
}
return instance;
}
}
4.6 session
如果服务器session失效时间(timeout)设置的太长,会引发内存泄露问题;

猜你喜欢

转载自1728197066.iteye.com/blog/2312216