什么情况下会导致内存泄露(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. webpack-插件机制杂记

    系列文章 Webpack系列-第一篇基础杂记 webpack系列-插件机制杂记 前言 webpack本身并不难,他所完成的各种复杂炫酷的功能都依赖于他的插件机制.或许我们在日常的开发需求中并不需要自己 ...

  2. SpringCloud-config分布式配置中心

    为什么要统一管理微服务配置? 随着微服务不断的增多,每个微服务都有自己对应的配置文件.在研发过程中有测试环境.UAT环境.生产环境,因此每个微服务又对应至少三个不同环境的配置文件.这么多的配置文件,如 ...

  3. JAVA_新建一个方法并且求三个数中的最大值

    package wac.wev.as;//新建一个方法在求最大值import java.util.Scanner; public class MaxLian {public static void m ...

  4. TrieTree

    学习链接:https://blog.csdn.net/lisonglisonglisong/article/details/45584721 前缀树解决字符串前缀匹配问题,查找单词是否存在,统计以如“ ...

  5. jQuery内容过滤选择器与子元素过滤选择器用法实例分析

    jQuery选择器内容过滤 一.:contains(text) 选择器::contains(text)描述:匹配包含给定文本的元素返回值:元素集合 示例: ? 1 2 $("div.mini ...

  6. asp.net core 自定义认证方式--请求头认证

    asp.net core 自定义认证方式--请求头认证 Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思 ...

  7. VS打开项目或解决方案卡死,一直处于未响应状态。

    1.背景:接手公司新项目时,无论用vs2013还是用vs2017都打开不了 2.解决办法:先把.suo文件删掉, 结果:vs2013可以打开,vs2017依旧打不开. 3.继续解决:上网搜了一下,把隐 ...

  8. 好代码是管出来的——使用GitHub实现简单的CI/CD

    软件开发一般来说是一项团队作业,在本系列文章开始就提到过软件的编码是由一个团队“并行”完成的,为了保证编码任务正常完成,首先引入版本控制工具来完成代码管理,为了保证代码质量引入了代码分析器以及代码测试 ...

  9. 数据库原理 - 序列4 - 事务是如何实现的? - Redo Log解析(续)

    > 本文节选自<软件架构设计:大型网站技术架构与业务架构融合之道>第6.4章节. 作者微信公众号:> 架构之道与术.进入后,可以加入书友群,与作者和其他读者进行深入讨论.也可以 ...

  10. nginx笔记----解决windows80端口被iis占用

    打开注册表:regedit HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP 数值数据修改成0或者其他 然后重启