android内存泄露MAT分析心得与注意点

       最近工作项目中出现了内存泄露,于是找来MAT分析,学习了下。之前学习使用MAT时一直不知道怎么分析,啥时候获取hprof文件等,一直对MAT的使用感觉云里雾里,直到昨天,成功的解决了内存泄露的问题才稍稍知道了。

      具体怎么分析推荐两篇文章,一篇郭大神的http://blog.csdn.net/guolin_blog/article/details/42238633,一篇夏大神的http://blog.csdn.net/xiaanming/article/details/42396507 我也是看的这两篇文章才慢慢懂了。这两篇文章里面都对MAT的分析讲的很清楚,但有个问题,两者都没有提到,就是在什么时候去dump java heap.正是这个重要的点没有讲到,我一直对MAT感觉是块鸡肋,一直不知道怎么使用。

        首先要注意的是如果你要排查一个类里面的内存泄露,你首先要退出这个类的时候去dump java heap ,否则如果你在这个类里面时,取得文件去分析时仍然有小红点(小红点是啥意思,具体参考上述郭大神博客),因为这个类正在被使用,所以他肯定没释放。(之前因为这个,在没有内存泄露的时候去分析hprof文件,却发现了红点,疑惑了好久)同时去dump java heap 之前要initiate gc ,如果不的话在mat的Histogram视图里面搜怀疑没释放的类的实例个数时,可能依然有多个,但在其排除软、弱、虚引用后的Path to GC root上却没有发现有表明可能存在泄露的地方。这时就会让人很疑惑,没找到内存泄露的地方,但实例却有多个,这个怎么回事呢,到底有没有泄露呢。这里我的结论是没有泄露也可能有多个实例存在,因为系统没有立刻进行垃圾回收啊,所以你在dump java heap 之前记得点下initiate gc ,过一会然后再去获取hprof文件去分析,这个时候如果仍然存在多个实例,那就说明很可能有泄露了。

在使用handler作为内部类的时候,你会得到这样的提示

handler should be static or leaks might occur

,去测试了下


MainActivity.java

public classMainActivityextendsAppCompatActivity{

MyHandlermyHandler;

@Override

protected voidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Buttonbutton=(Button)findViewById(R.id.button);

myHandler=newMyHandler();

myHandler.sendEmptyMessageDelayed(0,10*1000);

button.setOnClickListener(newView.OnClickListener() {

@Override

public voidonClick(View v) {

Intentintent=newIntent(MainActivity.this,Main2Activity.class);

startActivity(intent);

MainActivity.this.finish();

}

});

}

@Override

protected voidonDestroy() {

super.onDestroy();

Log.v("PLU","-----onDestroy");

//  myHandler.removeCallbacksAndMessages(null);

}

classMyHandlerextendsHandler{

//WeakReference wf;

// public MyHandler(MainActivity mainActivity){

// wf=new WeakReference(mainActivity);

// }

@Override

public voidhandleMessage(Message msg) {

super.handleMessage(msg);

// MainActivity mainActivity=wf.get();

// mainActivity.log();

log();

}

}

public voidlog(){

Log.v("PLU","I AM HANDLER ");

}

}


Main2Activity.java

public classMain2ActivityextendsAppCompatActivity{

@Override

protected voidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main2);

TextViewtextView=(TextView)findViewById(R.id.tv);

textView.setOnClickListener(newView.OnClickListener() {

@Override

public voidonClick(View v) {

Intentintent=newIntent(Main2Activity.this,MainActivity.class);

startActivity(intent);

Main2Activity.this.finish();

}

});

}

}

在onDestroy时没有调handler.removeMessageAndCallback, 在两个Activity之间多次跳转后,调到Main2Activity页面,点击initiate GC后点击dump java heap ,转成标准文件后在MAT里面分析,发现MainActiivty的实例为0个,为什么我没有写成注释掉的那种WeakRefrence引用的写法也没有发生内存泄露呢,主要官方说的may occur leak ,不是说一定会,是因为执行完了就释放了,只是释放的晚一些。在调到Main2Activity页面时此时MainActivity类还没有释放,可以看到仍然有打印MainActivity里面的log,在处理完消息后MainActivity也释放了,如果MainActivity里面handler的handleMessage里面是个死循环一直在打印的话,那MainActivity就一直存在,就释放不掉。在多次切换后就会发生内存泄露,Mat分析时会发现handler持有MainActiivty,存在多个MainActivity实例。想当然的认为,如果将MainActivity的onDestroy的myHandler.removeCallbacksAndMessages(null);解开注释的话,MainActivity也不会发生内存泄露,不会有多个MainActivity实例。后来测试下发现自己错了。该Message在消息队列里面无限循环,导致点击按钮都没有反应。后来将MainActivity.java的内容改为下面这样,


public classMainActivityextendsAppCompatActivity{

MyHandlermyHandler;

HandlerThreadhandlerThread;

@Override

protected voidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Buttonbutton=(Button)findViewById(R.id.button);

handlerThread=newHandlerThread("plu");

handlerThread.start();

myHandler=newMyHandler(MainActivity.this,handlerThread.getLooper());

myHandler.sendEmptyMessageDelayed(0,10*1000);

button.setOnClickListener(newView.OnClickListener() {

@Override

public voidonClick(View v) {

Intentintent= newIntent(MainActivity.this,Main2Activity.class);

startActivity(intent);

MainActivity.this.finish();

}

});

}

@Override

protected voidonDestroy() {

super.onDestroy();

Log.v("PLU","-----onDestroy");

isRunning=false;

myHandler.removeCallbacksAndMessages(null);

handlerThread.quit();

}

static classMyHandlerextendsHandler{

WeakReferencewf;

publicMyHandler(MainActivity mainActivity,Looper looper){

super(looper);

wf=newWeakReference(mainActivity);

}

@Override

public voidhandleMessage(Message msg) {

super.handleMessage(msg);

MainActivitymainActivity=wf.get();

// mainActivity.log();

while(true) {

mainActivity.log();

}

}

}

public voidlog(){

Log.v("PLU","I AM HANDLER ");

}

}

再来回切换Activity,发现仍然会有内存泄露。又陷入疑惑中,难道死循环导致即使使用WeakRefrence,置为静态内部类,也无法回收外部Activity吗,当然实际开发中是不会有这样的需求的。只是为了更好地理解。

临时的结论是

1.即使MAT中同一类存在多个实例,也不一定就是发生可内存泄露,也许是你获取hprof文件之前没有调用initiate gc操作,系统刚好还没有去回收并不代表着回收不掉。

2.在执行死循环的内部类里面,即使将该内部类置为静态的,且使用若引用持有外部类引用,也会导致内存泄露。程序中一定要小心死循环。

3.在Android Studio 点击dump java heap 时,要处于离开怀疑泄露类页面,且点击initiate gc 后再去获取hprof文件。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容