星空网 > 软件开发 > 操作系统

Android 内存泄漏的一些情况。

最近在维护代码,发现一个自定义View(这个View是在一个AsyncTask的工作线程doInBackground中新建的,在UI线程onPostExecute中添加进window中的)经常会泄漏内存,导致其引用的Activity一直得不到释放,每次退出再进去都会导致Activity的对象+1.

package com.xxx.launcher.view;import android.content.Context;import android.util.Log;import android.view.View;public class WeatherTextView extends SkinTextView {  public WeatherTextView (Context context) {
super(context); postDelayed(mShowCityRunnable, 200);//这一步有问题 } @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); if (visibility == View.VISIBLE) { post(mShowCityRunnable); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); onCancel(); }; public void onCancel(){ removeCallbacks(mShowCityRunnable); } private Runnable mShowCityRunnable = new Runnable() { @Override public void run() { Log.i("mShowCityRunnable-------TAG", "run"+mShowCityRunnable); setText(city); } };}

 

Android 内存泄漏的一些情况。images/loading.gif' data-original="http://images2015.cnblogs.com/blog/895828/201609/895828-20160901135510996-1054511246.jpg" />

最后通过MAT工具查看内存快照的比较,发现了如下的情况,把内存泄露的地方锁定在了WeatherTextView$2的第二个内部类中mShowCityRunnable ,一开始始终都想不到这个内部类到底有什么地方泄露了,最后突然灵光一闪,是不是View的post()方法导致的,在网上一查,发现确实。

public boolean post(Runnable action) {   Handler handler;   AttachInfo attachInfo = mAttachInfo;   if (attachInfo != null) {     handler = attachInfo.mHandler;   } else {     // Assume that post will succeed later     ViewRootImpl.getRunQueue().post(action);     return true;   }    return handler.post(action); } 

在post() 函数注释中,明确写着:This method can be invoked from outside of the UI thread only when this View is attached to a window.

当View还没有attach到当前window时,mAttachInfo 值为 null,故而执行 else语句,再看一下getRunQueue()和其post() 方法:

static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();  static RunQueue getRunQueue() {    RunQueue rq = sRunQueues.get();    if (rq != null) {      return rq;    }    rq = new RunQueue();    sRunQueues.set(rq);    return rq;  }  ……  static final class RunQueue {    private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();     void post(Runnable action) {      postDelayed(action, 0);    }     void postDelayed(Runnable action, long delayMillis) {      HandlerAction handlerAction = new HandlerAction();      handlerAction.action = action;      handlerAction.delay = delayMillis;       synchronized (mActions) {        mActions.add(handlerAction);      }    }        void executeActions(Handler handler) {      synchronized (mActions) {        final ArrayList<handleraction> actions = mActions;        final int count = actions.size();         for (int i = 0; i < count; i++) {          final HandlerAction handlerAction = actions.get(i);          handler.postDelayed(handlerAction.action, handlerAction.delay);        }         actions.clear();      }    }    ……  } 

这样会把Runnable 插入到一个静态的ThreadLocal的RunQueue队列里(在工作线程中post,就会插入工作线程的RunQueue队列),针对本文开头给出的例子,那么插入的Runnable什么时候得到执行呢?

调用RunQueue.executeActions()方法只有一处,即在ViewRootImpl类的如下非静态方法中

private void performTraversals() {        if (mLayoutRequested && !mStopped) {       // Execute enqueued actions on every layout in case a view that was detached       // enqueued an action after being detached       getRunQueue().executeActions(attachInfo.mHandler);     } } 

该方法是在UI线程执行的(见ViewRootImpl.handleMessage()), 故当UI线程执行到该performTraversals() 里的 getRunQueue() 时,得到的是UI线程中的RunQueue,这样AsyncTask 线程中的 RunQueue永远不会被执行到, 并且AsyncTask的是用线程池实现的,AsyncTask启动的线程会长期存在,造成如下引用关系:

 

AsyncTask线程 => 静态的ThreadLocal的RunQueue => Runnable => View=> Activity;

如此即使activity finish 了,确始终存在一个静态引用链引用这该activity,而 Activity一般又引用着很多资源,比如图片等,最终造成严重资源泄漏。

最后我是写改成

package com.xxx.launcher.view;import android.content.Context;import android.util.Log;import android.view.View;public class WeatherTextView extends SkinTextView {  public WeatherTextView (Context context) {    super(context);  }    @Override  protected void onAttachedToWindow() {    super.onAttachedToWindow();    postDelayed(mShowCityRunnable, 200); //在onAttachedToWindow方法中执行post方法  }    @Override  protected void onWindowVisibilityChanged(int visibility) {    super.onWindowVisibilityChanged(visibility);      if (visibility == View.VISIBLE) {      post(mShowCityRunnable);    }  }    @Override  protected void onDetachedFromWindow() {    super.onDetachedFromWindow();    onCancel();  };    public void onCancel(){    removeCallbacks(mShowCityRunnable);  }  private Runnable mShowCityRunnable = new Runnable() {    @Override    public void run() {      Log.i("mShowCityRunnable-------TAG", "run"+mShowCityRunnable);      setText(city);    }  };}

Android 内存泄漏的一些情况。

Android 内存泄漏的一些情况。

 

这样Activity就没有再被其他东西引用了,就不会发生Activity的泄漏了,Activity就可以被释放了。这样,不管进入退出进入这个MainMenuActivity多少次,MainMenuActivity的对象就只会保存一份。

ps:至于为什么在两个Histogram(直方图)的比较图中还是显示MainMenuActivity+1,则是因为这是类名,类被加载之后,在进程结束之前不会被回收

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

===============================================================================================================================

===============================================================================================================================

 

Android 内存泄漏的一些情况。

这种泄漏一般是因为mStorageManager 注册了但是没有取消注册

mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);mStorageManager.registerListener(mStoragelistener);

取消注册就可以了

if (mStorageManager != null) {  mStorageManager.unregisterListener(mStoragelistener);}

 

 




原标题:Android 内存泄漏的一些情况。

关键词:Android

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

Shopee 双11大促破纪录 5分钟售出1100万件:https://www.goluckyvip.com/news/5484.html
shopee注册需要店铺流水吗?shopee注册对流水有什么要求?:https://www.goluckyvip.com/news/5485.html
TikTok 动态展示广告:在 TikTok 上宣传产品最简单的方法:https://www.goluckyvip.com/news/5486.html
跨物云国际物流:https://www.goluckyvip.com/news/5487.html
Lazada双11破去年纪录 单笔订单金额高达1亿越南盾:https://www.goluckyvip.com/news/5488.html
东南亚电商发展趋势?2021年东南亚互联网经济报告出炉:https://www.goluckyvip.com/news/5489.html
如何用摄影作品表现“芳草鲜美,落英缤纷”的:https://www.vstour.cn/a/411247.html
70岁以上景区门票优惠70周岁还是虚岁?:https://www.vstour.cn/a/411248.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流