什么情况下会导致内存泄露(Memory Leak)?

Android 的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M。因此我们所能利用

的内存空间是有限的。如果我们的内存占用超过了一定的水平就会出现OutOfMemory 的错误。

内存溢出的几点原因:

1、资源释放问题
程序代码的问题,长期保持某些资源,如Context、Cursor、IO 流的引用,资源得不到释放造成内存泄露。

需要适当的释放资源的情况,这些硬件资源可能包括:视频、音频、相机等。

2、广播注册后没取消造成的内存泄漏

记得在activity销毁的时候一定要取消广播的注册

3、static 关键字的使用问题
static 是Java 中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。

所以用static 修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(Context 的情况最多),

这时就要谨慎对待了。

public class ClassName {
private static Context mContext;
//省略
}
以上的代码是很危险的,如果将Activity 赋值到mContext 的话。那么即使该Activity 已经onDestroy,

但是由于仍有对象保存它的引用,因此该Activity 依然不会被释放。

我们举Android 文档中的一个例子。

private static Drawable sBackground;
  @Override
  protected void onCreate(Bundle state) {
  super.onCreate(state);
  TextView label = new TextView(this);
  label.setText("Leaks are bad");
  if (sBackground == null) {
    sBackground = getDrawable(R.drawable.large_bitmap);
  }
  label.setBackgroundDrawable(sBackground);
  setContentView(label);
}
sBackground 是一个静态的变量,但是我们发现,我们并没有显式的保存Contex 的引用,但是,当Drawable
与View 连接之后,Drawable 就将View 设置为一个回调,由于View 中是包含Context 的引用的,所以,实
际上我们依然保存了Context 的引用。这个引用链如下:Drawable->TextView->Context
所以,最终该Context 也没有得到释放,发生了内存泄露。
针对static 的解决方案
① 应该尽量避免static 成员变量引用资源耗费过多的实例,比如Context。
② 此时的Context 尽量使用ApplicationContext,因为Application 的Context 的生命周期比较长,引用它不会出现内存泄露的问题。
③ 使用WeakReference 代替强引用。比如可以使用WeakReference<Context> mContextRef;

4、线程导致内存溢出
线程产生内存泄露的主要原因在于线程生命周期的不可控。我们来考虑下面一段代码。

public class MyActivity extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  new MyThread().start();
  }
private class MyThread extends Thread{
  @Override
  public void run() {
  super.run();
  //do somthing
    }
  }
}
这段代码很平常也很简单,是我们经常使用的形式。我们思考一个问题:假设MyThread 的run 函数是一个很费
时的操作,当我们开启该线程后,将设备的横屏变为了竖屏,一般情况下当屏幕转换时会重新创建Activity,按照我
们的想法,老的Activity 应该会被销毁才对,然而事实上并非如此。
由于我们的线程是Activity 的内部类,所以MyThread 中保存了Activity 的一个引用,当MyThread 的run 函
数没有结束时,MyThread 是不会被销毁的,因此它所引用的老的Activity 也不会被销毁,因此就出现了内存泄露的问题。

有些人喜欢用Android 提供的AsyncTask,但事实上AsyncTask 的问题更加严重,Thread 只有在run 函数不结
束时才出现这种内存泄露问题,然而AsyncTask 内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread 对
象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask 作为Activity 的内部类,就更容易出现内存泄露的问题。
针对这种线程导致的内存泄露问题的解决方案:
①  将线程的内部类,改为静态内部类(因为非静态内部类拥有外部类对象的强引用,而静态类则不拥有)。
在线程内部采用弱引用保存Context 引用。

5、Handler内存泄漏
Handler作为内部类存在于Activity中,但是Handler生命周期与Activity生命周期往往并不是相同的,比如当Handler对象有Message在排队,则无法释放,进而导致本该释放的Acitivity也没有办法进行回收。 解决办法:

① 在onDestroy里移除msg或callback

② 声明handler为static类,这样内部类就不再持有外部类的引用了,就不会阻塞Activity的释放

③ 如果内部类实在需要用到外部类的对象,可在其内部声明一个弱引用引用外部类。

6、使用application的context来替代activity

这是一个很隐晦的内存泄漏的情况。有一种简单的方法来避免context相关的内存泄漏,最显著地一个是避免context逃出他自己的范围之外,使用Application context,这个context的生存周期和你的应用的生存周期一样长,而不是取决于activity的生存周期。如果你想保持一个长期生存的对象,并且这个对象需要一个context,记得使用application对象。

7、集合中对象没清理造成的内存泄漏

我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。

如果这个集合是static的话,那情况就更严重了。

附:

1.微信团队原创分享:Android内存泄漏监控和优化技巧总结

2. Android内存泄漏的检测流程、捕捉以及分析

内存泄漏(Memory Leak)的更多相关文章

  1. 堆(heap)和栈(stack)、内存泄漏(memory leak)和内存溢出

    来源:http://blog.itpub.net/8797129/viewspace-693648/ 简单的可以理解为:heap:是由malloc之类函数分配的空间所在地.地址是由低向高增长的.sta ...

  2. Android 内存管理 &Memory Leak & OOM 分析

    转载博客:http://blog.csdn.net/vshuang/article/details/39647167 1.Android 进程管理&内存 Android主要应用在嵌入式设备当中 ...

  3. 内存溢出(Oom)和内存泄露(Memory leak)

    1.概念 内存溢出(Oom):1.内存不够用:2.数据长度短的数据类型存储了一个数据长度较大的数据类型:3.一个结果 内存泄露(Memory leak):1.忘记释放已用内存,内存管理较为常见的现象: ...

  4. SQL Server 内存泄露(memory leak)——游标导致的内存问题

    原文:SQL Server 内存泄露(memory leak)--游标导致的内存问题 转自:http://blogs.msdn.com/b/apgcdsd/archive/2011/07/01/sql ...

  5. 内存泄漏 Memory Leaks 内存优化 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  6. malloc(50) 内存泄露 内存溢出 memory leak会最终会导致out of memory

    https://en.wikipedia.org/wiki/Memory_leak In computer science, a memory leak is a type of resource l ...

  7. 内存溢出(Memory Overflow)和内存泄露(Memory Leak)的区别

    内存泄漏指你用malloc或new申请了一块内存,但是没有通过free或delete将内存释放,导致这块内存一直处于占用状态 内存溢出指你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数 ...

  8. python内存泄露memory leak排查记录

    问题描述 A服务,是一个检测MGR集群主节点是否发生变化的服务,使用python语言实现的. 针对每个集群,主线程会创建一个子线程,并由子线程去检测.子线程会频繁的创建和销毁. 上线以后,由于经常会有 ...

  9. 利用linux的mtrace命令定位内存泄露(Memory Leak)

    一谈到内存泄露, 多数程序猿都闻之色变. 没错, 内存泄露非常easy引入. 但非常难定位.  以你我的手机为例(如果不常常关机). 如果每天泄露一些内存, 那么開始的一个星期, 你会发现手机好好的. ...

随机推荐

  1. 4.3dotnet watch run「深入浅出ASP.NET Core系列」

    希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,谢谢关注. dotnet run的麻烦 如果您使用的是vs code进行跨平台开发,那么dotnet watch run对你的 ...

  2. springcloud情操陶冶-springcloud config server(一)

    承接前文springcloud情操陶冶-springcloud context(二),本文将在前文基础上浅析下ConfigServer的工作原理 前话 根据前文得知,bootstrapContext引 ...

  3. nginx优化之配置文件优化一常用参数

    #定义nginx运行的用户和用户组 user www www;   #启动进程,通常设置成和cpu的数量相等 worker_processes 8 ;   #为每个进程分配CPU,上面京8个进程分配到 ...

  4. [转]Blue Prism Login Agent 使用指导手册

    本文转自:https://cloud.tencent.com/developer/news/83035 咳!咳!咳! 第一篇RPA技术文,还是贼拉鸡冻.各位大侠要多多支持啊 1.Login Agent ...

  5. C# 读取PDF多级书签

    在PDF中,书签作为一种导航的有效工具,能帮助我们快速地定位到文档中的指定段落.同时,书签也能让人对文档结构一目了然,在某种程度上也可作为目录使用.对于C#操作PDF中的书签,在上一篇文章中介绍了具体 ...

  6. 基于Springboot集成security、oauth2实现认证鉴权、资源管理

    1.Oauth2简介 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAu ...

  7. CSRF & CORS

    下面转的两篇文章分别说明了以下两个概念和一些解决方法: 1. CSRF - Cross-Site Request Forgery - 跨站请求伪造 2. CORS - Cross Origin Res ...

  8. ES6基础(二)

    一.ES6字符串扩展 字符串模板 在传统的JavaScript语言中,输出模板通常是这样写的. 上面这种写法繁琐不方便,于是ES6中引入了字符串模板解决这个问题. 用反引号(`)标识.他可以当做普通字 ...

  9. 【English】七、常见动词

    一.动词: touch.hear.say.listen touch [tʌtʃ] 触摸 I touch the cat. They touch the elephant. hear  [hɪr] 听到 ...

  10. SpringMVC归纳-1(model数据模型与重定向传参技术)

    要点: model是一个Map结构的数据模型,能重定向时传递数据(拼接URL),但不安全,主要用于渲染前端页面,配合Thymeleaf填充html里面里设置好的参数. @RequestParam用来获 ...