内存泄漏、资源泄漏、空指针等问题的分析与总结

来源:互联网 发布:linq.js where. First 编辑:程序博客网 时间:2024/05/20 04:27

一、内存泄漏ACTIVITY_LEAK

1、静态变量持有Activity对象,导致Activity无法释放   

  1  2  3  4  5  6  7  8  9 10 11 12 13
public class MainActivity extends Activity{
private static Context mContext;
private static View mView;
@override
protected void onCreated(Bundle savedInstatenceState){
super.onCreated(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this; //..........1
mView = new View(this); //..........2
}

}
因为静态变量的生命周期与JVM相同(与application相同),导致Context生命周期(activity的生命周期)与与JVM相同(与application相同)


解决方法:杜绝静态变量持有activity


 2、单例模式持有Activity对象,导致Activity无法释放

         

在GameNotFreeFlowDialogActivity.onCreate方法中调用了单例类FreeFlowUtil的showMessageDialog()方法,

其中FreeFlowUtil的showMessageDialog()方法中第一个参数需要传入Context类。 

由于FreeFlowUtil类为单例模式,生命周期与JVM相同(与application相同),在FreeFlowUtil类创建了mChinaUnicomAlertDialog对象并传入了GameNotFreeFlowDialogActivity的Context,导致Context生命周期(GameNotFreeFlowDialogActivity的生命周期)同FreeFlowUtil相同,导致了泄漏问题。

解决方法:

方法一:不用单例模式   

方法二:将Activity的Context改为Application的Context:getApplicationContext(),这样单例模式持有的就不是单个activity了

注意:不是所有的Activity的Context都可以替换为getApplicationContext(),getApplicationContext()在startActivity时要新建task,而且在任何时候都不能创建dialog


 3、属性无限循环动画持有了Activity里的View,View持有Activity对象,导致Activity无法释放

属性动画中的无限循环动画,在activity的onDestroy中没有停止,导致动画持有了activity的view,view又持有了activity

解决方法:在activity的onDestroy中停止动画


4、  handler导致的内存泄漏(非静态内部类持有外部类的引用导致的内存泄漏)

当handler内部类在不停的处理消息,或者handler内部类在消息发送很长一段时间才处理,会导致内存泄漏。

由于handler是非静态内部类他是一定会持有外部类的引用的,它又在不停的处理消息(或者当activity不可见是它仍在处理消息),所以它一直持有activity对象,导致Activity无法释放


在 Java 语言中,非静态内部类、匿名内部类将持有一个对外部类的隐式引用,而静态内部类则不会持有一个对外部类的隐式引用

解决方法:

方法一:所以要将handler内部类改为静态内部类;如果需要传入外部类的对象,那么hanler初始化时传入外部类的对象要是弱引用;将所有引用的外部类成员使用WeakReference对象

方法二:在activity的onDestroy的时候手动清除Message

@Override    protected void onDestroy() {        super.onDestroy();         mHandler.removeCallbacksAndMessages(null);  // 需要在Activity生命周期结束时清除掉CallbacksAndMessages    }

5、小结

禁止任何生命周期与activity生命周期不一致的结构持有activity,结构包括(静态变量、单例模式、动画、生命周期不一致的非静态内部类、匿名类)。有人说了那静态内部类不也和activity生命周期不一致吗,因为是静态不要紧啊只要不持有activity就没事啊,静态内部类则不会持有一个对外部类的隐式引用。所以只要不持有就没事。

6、其他解决内存泄漏优化内存的方法


(1)java中的基本方法

*使用字符串与包装类时,尽量用直接量创建

*使用StringBuilder和StringBuffer进行字符串连接(而不用String,因为会造成多个对象)

*尽早释放无用的对象引用(及时赋为null)

*尽量少用静态变量

*避免在循环中创建java对象

*缓存经常使用的对象(使用hashmap缓存)

*考虑弱引用、软引用

(2)android中的方法

* 布局尽量减少层级

*布局尽量减少颜色重绘

*默认图片以加载的形式加载,不放在布局background中

*缩小图片大小,能用.9图的用.9图


二、资源泄漏(RESOURCE_LEAK

及时对资源进行关闭,对于Try catch语句,需要在Finally分支下保证关闭。

public static String getFileMD5(File file) {if (!file.isFile()) {return null;}MessageDigest digest = null;FileInputStream in = null;byte buffer[] = new byte[1024];int len;try {digest = MessageDigest.getInstance("MD5");in = new FileInputStream(file);while ((len = in.read(buffer, 0, 1024)) != -1) {digest.update(buffer, 0, len);}} catch (Exception e) {e.printStackTrace();return null;}finally {CommonUtils.closeQuietly(in);  //及时关闭}return bytesToHexString(digest.digest());}
  /** * 静默关闭申请资源,防止产生 RESOURCE_LEAK * @param closeable */public static void closeQuietly(Closeable closeable) {if (closeable != null) {try {closeable.close();} catch (Exception ex) {// TODO: 2016/1/15 Log or ignore}}}
三、空指针(NULL_DEREFERENCE

一般未对引用判空鉴定。判空即可


0 0