关于Android应用内存泄漏MAT分析使用

来源:互联网 发布:java程序员太多了知乎 编辑:程序博客网 时间:2024/06/05 19:53

      无意中发现,自己写的应用退出,进入,重复不到10次,就会异常挂掉,查看logcat,竟然没有明显的信息,似乎只看到了一个关键词:GC,free16%.这像是内存出问题了。于是百度之:Android 内存泄漏。文章看了不下百篇,查原因都建议MAT?啥是MAT,再百度之,原来是eclipse的查看内存泄漏的插件,感觉自己立马变大牛啊!用法步骤网上给得很全Android MAT的使用方式:点击打开链接。

      第一:查了内存泄漏的对象,多到崩溃,最主要的似乎是mContext的泄漏,关于上下文泄漏,网上基本有几个总结:1.非静态类用了静态类,然后静态类中引用了mContext,造成activity无法释放内存。(因为静态类的资源是不会释放的,所以导致本来要退出的activity也无法回收资源,被强引用了,)此时的方法就是使用Context.getApplicationContext()。2.当然如果是资源文件必须要activity的上下文,也只有强制使用弱引用比如这样:Weakference<Context> context = new Weakference<Context>(mContext)。具体用法再去百度吧,我这边的重点不是这个。

      第二:另外还有内存泄漏是因为Android中不建议使用枚举类,枚举类比一般的静态常量占用2倍以上内存。

      第三:我的应用内存泄漏了,根据百度的文章,我自作主张的在退出应用的时候,把能赋值为null的都赋值为null了,但是却在退出的时候造成了一个空指针异常的错误,是关于我使用了mHandler传递消息,当我应用退出的时候调用onDestroy后,将mHandler=null 了,但是延迟发送的消息还没有执行,这时必然空指针异常。继续百度学习吧,原来handler也是很容易造成内存泄漏的,所以在onDestroy中不能直接将mHandler=null ,而是要mHandler.removeCallbacksAndMessages(null)。

      第四:以上方法,使用完毕,我的应用重复进入,退出,进入,退出,还是6次就挂了。我能怎么办,我也很绝望啊。

      重点来了!重点来了!重点来了!(重要的事都说要说三遍)

      为了解决这个顽疾bug。我发现了一个没有办法的办法,那就是如何在20次重复启动过程中不挂掉,就算我赢了。好吧,正题:

直接上代码先

package com.settings.net;import com.settings.net.R;import android.annotation.SuppressLint;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.KeyEvent;public class MActivity extends Activity{    private static final String TAG = "NetworkSettingsActivity";    private Context mContext = null;    private boolean isFromSetting;
    private boolean isResume = false;
    private static final int COMPLETED_INIT_RESOURCE = 100;/*频繁操作进入退出,会造成前次资源未加载完,所以退出的时候还没来得及释放,第二次又加载一次,导致内存溢出。所以加一个定时操作,控制back按键的响应,防止频繁操作退出。*/
    private final Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            switch (msg.what) {                case COMPLETED_INIT_RESOURCE:                    isResume = true;                    break;                default:                    break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.page_display);        mContext = MtActivity.this;        isFromSetting = getIntent().getBooleanExtra("FromSetting", false);
        mHandler.sendEmptyMessageDelayed(COMPLETED_INIT_RESOURCE, 3500);/*这里控制初始资源的延迟时间为3500ms,在不影响用户体验的前提下,可以随意设置。*/    }    @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {        if (keyCode == KeyEvent.KEYCODE_BACK) {
          if(isResume){/*资源加载未完成,返回键不起作用。*/            /*************start ,don't change the location,avoid Memory leak********** */            finish();            if (isFromSetting) {                Intent intent = new Intent();                intent.setAction("com.settings.SETTINGS");                intent.putExtra("gridViewSelect", 5);                startActivity(intent);            }            System.exit(0);            /*************end ,don't change the location,avoid Memory leak********** */
            }            return true;        }        return super.onKeyDown(keyCode, event);    }    @Override    protected void onResume() {        super.onResume();    }    protected void onPause() {        super.onPause();    }    @Override    protected void onDestroy() {        super.onDestroy();        mContext = null;        /*************start ,don't change the location,avoid Memory leak********** */        android.os.Process.killProcess(android.os.Process.myPid());        System.gc();           /*************end ,don't change the location,avoid Memory leak********** */    }}

关键就是我那几句注释框起来的代码了,总结起来就是1:先结束自生activity,然他们先走 onPause()把该置null的置成null,改取消的广播取消掉,该关闭的数据流关闭,该移除的handler移除,还有图片资源该回收的回收,比如这样的也容易内存泄漏:

Resources resources = ctvContext.getResources();

Drawable drawable = resources.getDrawable(R.drawable.transparency_bg);

       

 w.setBackgroundDrawable(drawable);

       

 drawable.setCallback(null);//关键代码是这句。

2:启动另一个要跳转回去的activity,然后再调用System.exit(0)。这句代码很厉害,是系统的强制退出的一个代码。如果先跳转activity再调用finish(),和System.exit(0),会发现我们自己的应用出现了一个空白时间,才调出要跳转回去的activity。所以我自己测试得出应该是要先正常流程结束activity自己一次,然后启动要跳转的应用,使得要跳转的应用界面先起来,然后再用户不可见的系统强制退出activity自己一次。

3:最后为了保险起见,我还是担心用户操作过快,退出应用的时候,我的服务还没来得及关闭什么的,所以我就在onDestroy()强制杀死了我自己的进程,再System.gc()一次,其实我发现这个System.gc(),真是一点用没有。。。。


内存泄漏的坑填完了,感觉自己又get到了新技能,还是棒棒的。



   



原创粉丝点击