什么情况下会导致内存泄露(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. C# 曲线上的点(二) 获取距离最近的点

    如何在一条曲线上,获取到距离指定点最近的点位置? 与上一篇 C# 曲线上的点(一) 获取指定横坐标对应的纵坐标值 类似, 我们通过曲线上获取的密集点,通过俩点之间连线,获取连线上最近的点.我们能够获取 ...

  2. day09 css

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  3. Git日常须知

    基本操作: git init 初始化环境 git add . 管理文件 git status 查看状态 git diff 文件名 查看修改内容 git commit -m '' 提交文件 git lo ...

  4. 从0到1搭建AI中台

    文章发布于公号[数智物语] (ID:decision_engine),关注公号不错过每一篇干货. 转自 | 宜信技术学院 作者 | 井玉欣 导读:随着“数据中台”的提出和成功实践,各企业纷纷在“大中台 ...

  5. java----静态代理

    静态代理没啥好说的,直接上代码 package com.yk.aop.staticproxy; import org.junit.jupiter.api.Test; //1.接口 public int ...

  6. Android ble 蓝牙4.0 总结一

    本文介绍Android ble 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用,如果手机系统版本API level < 18,也是用不了蓝牙4.0的哦 ...

  7. 设计模式系列之装饰模式(Decorator Pattern)

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装.这种模式创建了一个装饰类,用来包装原 ...

  8. 使用免费 mongodb数据库 + 免费node.js服务器搭建小程序接口

    由于微信的小程序只支持不带端口的域名接口,不支持IP地址和接口,所以我们需要映射到80端口并绑定备案过的域名才能被微信小程序访问到.简单点就是接口需要 https 协议才行,找了许久的免费的数据库与n ...

  9. ztree搜索节点并展开

    web <div class="zTreeC"> <div class="searchL" lay-filter="searchL& ...

  10. js关于new Date() 日期格式

    下面是关于Date的对象 var oDay = new Date(); oDay.getYear(); //当前年份 oDay.getFullYear(); //完整的年月日(xx年,xx月,xx日) ...