避免Android内存泄露

摘自:http://blog.csdn.net/xyz_lmn/article/details/7108011

  Android的应用被限制为最多占用16m的内存,至少在T-Mobile G1上是这样的(当然现在已经有几百兆的内存可以用了——译者注)。它包括电话本身占用的和开发者可以使用的两部分。即使你没有占用全部内存的打算,你也应该尽量少的使用内存,以免别的应用在运行的时候关闭你的应用。Android能在内存中保持的应用越多,用户在切换应用的时候就越快。作为我的一项工作,我仔细研究了Android应用的内存泄露问题,大多数情况下它们是由同一个错误引起的,那就是对一个上下文(Context)保持了长时间的引用。

在Android中,上下文(Context)被用作很多操作中,但是大部分是载入和访问资源。这就是所有的widget都会在它们的构造函数中接受一个上下文(Context)参数。在一个合格的Android应用中,你通常能够用到两种上下文(Context):活动(Activity)和应用(Application)。活动(Activity)通常被传递给需要上下文(Context)参数的类或者方法:

[java] view plaincopyprint?

  1. @Override
  2. protected void onCreate(Bundle state) {
  3. super.onCreate(state);
  4. TextView label = new TextView(this);
  5. label.setText("Leaks are bad");
  6. setContentView(label);
  7. }

这就意味着那个View有一个对整个活动(Activity)的引用并且对这个活动(Activity)中保持的所有对象有保持了引用;通常它们包括整个View的层次和它的所有资源。因此,如果你“泄露”了上下文(Context)(这里“泄露”的意思是你保持了一个引用并且组织GC收集它),你将造成大量的内存泄露。如果你不够小心的话,“泄露”一整个活动(Activity)是件非常简单的事情。

当屏幕的方向改变时系统会默认的销毁当前的活动(Activity)并且创建一个新的并且保持了它的状态。这样的结果就是Android会从资源中重新载入应用的UI。现在想象一下,你写了一个应用,有一个非常大的位图,并且你并不想在每次旋转时都重新载入。保留它并且每次旋转不重新加载的最简单的办法就是把它保存在一个静态字段上:

[java] view plaincopyprint?

  1. private static Drawable sBackground;
  2. @Override
  3. protected void onCreate(Bundle state) {
  4. super.onCreate(state);
  5. TextView label = new TextView(this);
  6. label.setText("Leaks are bad");
  7. if (sBackground == null) {
  8. sBackground = getDrawable(R.drawable.large_bitmap);
  9. }
  10. label.setBackgroundDrawable(sBackground);
  11. setContentView(label);
  12. }

这段代码非常快,同时也错的够离谱。它泄露了当第一次屏幕角度改变时创建的第一个活动(Activity)。当一个Drawable被附加到一个View,这个View被设置为drawable的一个回调。在上面的代码片断中,这意味着这个Drawable对TextView有一个引用,同时这个TextView对Activity(Context对象)保持着引用,同时这个Activity对很多对象又有引用(这个多少还要看你的代码了)。

这个例子是造成Context泄露的最简单的一个原因,你可以看一下我们在主屏幕源码(查看unbindDrawables()方法)中是通过在Activity销毁时设置保存过的Drawable的回调为空来解决这个问题的。更为有趣的是,你可以创建一个context泄露的链,当然这非常的糟糕。它们可以让你飞快的用光所有的内存。

有两种简单的方法可以避免与context相关的内存泄露。最明显的一个就是避免在context的自身的范围外使用它。上面的例子展示了在类内部的一个静态的引用和它们对外部类的间接引用是非常危险的。第二个解决方案就是使用Application Context。这个context会伴随你的应用而存在,并且不依赖Activity的的生命周期。如果你计划保持一个需要context的长生命周期的对象,请记得考虑Application对象。你可以非常方便的通过调用Context.getApplicationContext() 或者 Activity.getApplication()获取它。

总之,为了避免涉及到context的内存泄露,请记住如下几点:

    1. 不要对一个Activity Context保持长生命周期的引用(一个对Activity的引用应该与Activity自身的生命周期相同)
    2. 尝试使用应用上下文(context-application)代替活动上下文(context-activity)
    3. 如果你不能控制它们的生命周期,在活动(Activity)中避免使用不是静态的内部类,使用静态类并且使用弱引用到活动(Activity)的内部。对于这个问题的解决方法是使用静态的内部类与一个弱引用(WeakReference)的外部类。就像ViewRoot和它的W内部类那么实现的。
    4. 垃圾回收器对于内存泄露来说并不是百分百保险的
时间: 2024-08-25 23:43:50

避免Android内存泄露的相关文章

android 内存泄露调试

一.概述 1 二.Android(Java)中常见的容易引起内存泄漏的不良代码 1 (一) 查询数据库没有关闭游标 2 (二) 构造Adapter时,没有使用缓存的 convertView 3 (三) Bitmap对象不在使用时调用recycle()释放内存 4 (四) 释放对象的引用 4 (五) 其他 5 三.内存监测工具 DDMS --> Heap 5 四.内存分析工具 MAT(Memory Analyzer Tool) 7 (一) 生成.hprof文件 7 (二) 使用MAT导入.hpro

Android内存泄露开篇

先来想这三个问题 内存泄露是怎么回事 内存会泄露的原因 避免内存泄露 1.内存泄露怎么回事 一个程序中,已经不需要使用某个对象,但是因为仍然有引用指向它垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造成了内存泄露. Android的一个应用程序的内存泄露对别的应用程序影响不大. 为了能够使得Android应用程序安全且快速的运行,Android的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进

android内存泄露调试,Heap,MAT

三.内存监测工具 DDMS --> Heap 无论怎么小心,想完全避免bad code是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方.Android tools中的DDMS就带有一个很不错的内存监测工具Heap(这里我使用eclipse的ADT插件,并以真机为例,在模拟器中的情况类似).用Heap监测应用进程使用内存情况的步骤如下: 1. 启动eclipse后,切换到DDMS透视图,并确认Devices视图.Heap视图都是打开的: 2. 将手机通过USB链接至电

Android内存泄露总结

Android可能发生内存泄露的地方总结: 1.查询数据库没有关闭游标 2.构建adapter时,没有使用缓存的convertView 3.Bitmap对象不使用的时候调用recycle()方法释放内存 4.释放对象的引用 5.单例模式引用context,如果使用actvitiy-context,会造成内存泄露, 可以使用getApplicationContext()); 或getApplication()代替. 参考文档: A?n?d?r?o?i?d? ?内?存?泄?漏?调?试 http://

Android内存泄露案例分析

一款优秀的Android应用,不仅要有完善的功能,也要有良好的体验,而性能是影响体验的一个重要因素.内存泄露是Android开发中常见的性能问题.这篇文章,通过我们曾经遇到的一个真实的案例,来讲述一个内存泄露问题,从发现到分析定位,再到最终解决的全过程. 这里把整个过程分为四个阶段: 第一阶段,现场勘查,分析Bug现象,找出有用线索: 第二阶段,初步推断,根据之前的线索,推断可能导致Bug的原因,并且进一步验证推断是否正确: 第三阶段,探究根源,找出导致Bug的真正原因: 第四阶段,解决方案,研

Android内存泄露分析简要思路

工作中遇到挺多需要分析内存泄露问题的情况,现在大致简要写下思路,等之后时间相对比较充裕再进行补充. 1.明白内存泄露的判断依据? 个人总结为:持续增加,只增不减! 理解一下这8个字,配合几个命令和工具来确定一下你的应用是否存在内存泄露问题,这是很关键的,如果一开始就判断错误了,那么没有继续往下进行的理由. 命令如下: adb shell dumpsys meminfo 应用包名 [当然,比较粗略地话,可以用adb shell procrank] 这时候你可以看到一个内存使用情况表 而我们首先关注

android 内存泄露小计

1   今天在调试android 程序时候,发现即使程序退出了,发现还占用内存大概有15M.用MAT查看,经过多次GC操作,发现依旧是15.直觉告诉我,应该发生内存泄露了.然后利用MAT,查看Memory Leak.结果让我很吃惊,发现是InputMethodManager.这个对象一直引用着Context.也就是Activity,导致它无法释放内存.后来google 一下发现, 以下贴出解决办法,希望给遇到类似情况的人,提供帮助: @Override protected void onDest

深入Android内存泄露

深入内存泄露 Android应用的内存泄露,其实就是java虚拟机的堆内存泄漏. 1.知识储备 1.Java内存模型 相关内存对象模型,参照博客精讲Java内存模型 1) 寄存器(register).这是最快的保存区域,这是主要由于它位于处理器内部.然而,寄存器的数量十分有限,所以寄存器是需要由编译器分配的.我们对此没有直接的控制权,也不可能在自己的程序里找到寄存器存在的任何踪迹. (2) 堆栈(stack).在执行函数(方法)时,函数一些内部变量的存储都可以放在栈上面创建,函数执行结束的时候这

Android 内存泄露检测工具 LeakCanary

LeakCanary 是 Android 和 Java 内存泄露检测框架.LeakCanary 可以用更加直白的方式将内存泄露展现在我们的面前. 开始使用 在 build.gradle 中加入引用,不同的编译使用不同的引用: ? 1 2 3 4 dependencies {    debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'    releaseCompile 'com.squareup.leakcanary:leak

Android 内存泄露

转:http://blog.chinaunix.net/uid-26930580-id-3844811.html 1.内存泄漏: 当出现对Activity.View或drawable等类的对象长期持有无用的引用,就会造成被引用的对象无法在GC时回收,而是长期占用堆空间,此时就会发生内存泄漏.简单来说,就是保留下来却永远不再使用的对象引用. 2.内存溢出: 如果应用程序在消耗光了所有的可用堆空间(16M到48M),那么再试图在堆上分配新对象时就会引起OOM(Out Of Memory Error)