用正确的姿势来说说Android上的内存泄漏问题

相信大家对App的内存管理都是相当关心的,在项目上线前的几天时间也会借助相关工具突击下严重的泄漏问题;

针对内存泄漏先提出几个疑问:

  • 什么是内存泄漏?
  • 内存泄漏带来的危害又是什么?
  • 哪些代码的写法会导致内存泄漏?
  • 如何找到泄露的地方,以及如何修复它?

一、什么是内存泄漏?
  • 无用的对象没有被及时释放引用,导致GC无法回收,就有可能出现内存泄漏。
二、内存泄漏带来的危害是什么?
  • 内存泄漏会增加内存占用和OOM几率。
三、哪些代码的写法会导致内存泄漏?
  • 常见五种导致 APP 内存泄漏的地方
    1. 静态 Activity
      泄漏 activity 最简单的方法就是在 activity 类中定义一个 static 变量,并且将其指向一个运行中的 activity 实例。如果在 activity 的生命周期结束之前,没有清除这个引用,那它就会泄漏了。这是因为 activity(例如 MainActivity) 的类对象是静态的,一旦加载,就会在 APP 运行时一直常驻内存,因此如果类对象不卸载,其静态成员就不会被垃圾回收。
    void setStaticActivity() {
      activity = this;
    }

    View saButton = findViewById(R.id.sa_button);
    saButton.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View v) {
            setStaticActivity();
            nextActivity();
      }
    });
 ![这里写图片描述](https://img-blog.csdn.net/20160712180226946)

2. 内部类或者匿名内部类
类似的,匿名类同样会持有定义它们的对象的引用。因此如果在 activity 内定义了一个匿名的 AsyncTask 对象,就有可能发生内存泄漏了。如果 activity 被销毁之后 AsyncTask 仍然在执行,那就会组织垃圾回收器回收 activity 对象,进而导致内存泄漏,直到执行结束才能回收 activity。

    void startAsyncTask() {
        new AsyncTask<Void, Void, Void>() {
            @Override protected Void doInBackground(Void... params) {
                while(true);
            }
        }.execute();
    }

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    View aicButton = findViewById(R.id.at_button);
    aicButton.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View v) {
            startAsyncTask();
            nextActivity();
        }
    });
 ![这里写图片描述](https://img-blog.csdn.net/20160712181354592)

3. Handlers
同样的,定义一个匿名的 Runnable 对象并将其提交到 Handler 上也可能导致 activity 泄漏。Runnable 对象间接地引用了定义它的 activity 对象,而它会被提交到 Handler 的 MessageQueue 中,如果它在 activity 销毁时还没有被处理,那就会导致 activity 泄漏了。

    void createHandler() {
        new Handler() {
            @Override public void handleMessage(Message message) {
                   super.handleMessage(message);
                }
            }.postDelayed(new Runnable() {
                @Override public void run() {
                        while(true);
                }
          }, Long.MAX_VALUE >> 1);
    }

    View hButton = findViewById(R.id.h_button);
    hButton.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) {
        createHandler();
        nextActivity();
        }
});
 ![这里写图片描述](https://img-blog.csdn.net/20160712183514777)

4. EditText
EditText所处的上下文对象会一直保留在(4.0.x,4.1.x,4.2.x)的系统版本中。大家在用着它这么长的时间不知道系统还有这么个bug(具体可参考:https://dddpaul.github.io/blog/2014/08/01/android-memory-leaks/),但好在Android 4.3, API 18的系统版本上修复了该问题,但是对于18以下的就要注意啦,需要做些特殊处理,不然就会导致泄漏的,其实解决办法也是很简单:修改EditText的android:inputType= “textNoSuggestions”
泄露的具体信息如图:
泄露信息

  1. Threads
    同样的,使用 Thread 和 TimerTask 也可能导致 activity 泄漏。
void spawnThread() {
        new Thread() {
            @Override public void run() {
                  while(true);
            }
        }.start();
    }

    View tButton = findViewById(R.id.t_button);
    tButton.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View v) {
          spawnThread();
          nextActivity();
      }
    });
 ![这里写图片描述](https://img-blog.csdn.net/20160712190045847)

注: 还有就是成对出现的方法或者页面销毁该销毁的销毁,该清空的清空

四、如何找到泄露的地方,以及修复它?
  • 借助相关工具,比如当下使用较多的LeakCanary,mat;

    1.LeakCanary的用法见:http://www.liaohuqiu.net/cn/posts/leak-canary-read-me/
    2.LeakCanary的github地址:https://github.com/square/leakcanary
    以上两个地址都有详细的介绍LeakCanary的使用和常见问题解答等功能,相信聪明的你们,很容易就能理解
    3.如果想深入分析泄漏原因的同学,需要Dump HPROF file,先将hprof文件pull到自己的电脑上,然后将文件直接拖到android studio的代码编辑页就能打开该文件,然后就可以漫漫的去品味它了


相关文章推荐:
http://wiki.jikexueyuan.com/project/android-actual-combat-skills/handler-using-possible-triggering-memory-leak.html
http://www.jianshu.com/p/cdc6d2e664f1
http://blog.csdn.net/u013034750/article/details/51460347

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值