Android OOM(Out of memory) 内存泄露基本知识

Android OOM(Out of memory) 内存泄露基本知识

转载至:http://blog.csdn.net/emilychai2010/article/details/12710135

1. 内存泄露

2. Android里的垃圾回收

3. Heap

4. 调试

5. 常见的内存泄露

1.什么是内存泄露(memory leak)?

A "memory leak" in your code is when you keep a reference to an object that is no longer needed。许多小白,类似我,会问,java不是有自己的垃圾回收机制吗,为什么还会发生内存泄露那?

2.Android里的垃圾回收?

垃圾回收是JAVA里的一个特性,正如我们所知,垃圾回收将会回收所有不能被GC root object所触及的对象。OOM的分析起点都是Garbage Collection Roots。任何可以通过GC root到达的对象会继续留在内存中,而那些通过GC root不能到达的对象则会被回收。比如下图,红色的是GC root,蓝色圆圈代表可以通过GC root到达的对象,黑色的就是会被GC回收的。蓝色的是留在内存中的,也就是OOM的发生点。

图1

GC root object包括:

(1)在当前调用栈里的对象,包括本地变量和方法参数

(2)JNI native references

(3)所有被引导程序(bootstrap Loader)所加载的类

(4)进程本身

在gingerbread之前,垃圾回收采用的是“stop the world”的策略,它的意思是当进行垃圾回收的时候,所有程序都必须停掉,进行整个Heap的回收;从gingerbread开始,垃圾回收采用的是同步回收机制,部分回收,暂停时间通常小于5ms.

举个例子,bitmap在honeycomb之前程序通过recycle(), finalizer进行回收,垃圾回收采用的事整个heap的回收,“stop the world”。在honeycomb之后,系统对bitmap的回收进行的同步的回收。

3.Heap

dalvik.vm.heapsize决定了Heap的大小。在gingerbread里,android引进了一项新的android:largeHeap,但是用这个选项的时候要慎重,是不是你的程序的确需要这么大的Heap?因为大Heap意味着的是更长时间的垃圾回收。

几个重要概念

Shallow heap:某个对象所消耗掉的内存。Retained set  of X: 当X垃圾回收进行时,一系列将被GC删除的对象集合。Retained heap of X:X保持的活跃内存。一个对象的Shallow heap是它在heap中的大小;而它的Retained heap指的是当这个对象进行垃圾回收的时候,heap中可以被释放掉的内存大小。比如下图2中,黄色原点的Shallow heap是100,Retained heap是400.

图2

Dominators:如果对象A统治着对象B,意味为通往B的每条路都要经过A。GC会回收所有没有被引用的对象。比如A在内存中被删除了,再也没有任何路可以通往B了,这个时候B就会被GC回收。

Dominator tree:用Dominators理念组织内存中对象的关系就是Dominator tree。tree的每个节点存储了可以被释放的内存。从这个树中你可以看出最大的一块回收内存和各个对象中依然保持活跃的依赖关系。

Reference对象


Strong reference


从不被GC回收的

Object o=new Object();

Object o1=o;


Soft reference


正常情况下不被GC回收,只在具有明显内存操作要求情况下被回收。

Memory-sensitive caches


Weak reference


可被GC回收。Weak reference是一种不够强大的reference,以至于它不能使对象强行留在内存中。如果一个对象只是被Weak referenced,意味着它随时可能被GC回收。

4.内存泄露调试

OOM和其他BUG不太一样的地方在于,LOG可能一点用处都没有。在发送OOM的时刻,整个系统处于内存饱和状态,某个程序挂掉是很正常的事情,所以LOG也没有什么太大的参考性,最重要的是hprof文件。它反映了这个时刻,内存的使用状况。我用Eclipse的MAT来分析hprof。

首先,Android手机里的hprof要转换成Eclipse的能识别的格式。android SDK自带有这个转换工具,在SDK的tools目录下输入这个命令,将手机中的outofmemory0.hprof转换成Eclipse可识别的new.hprof。

[java] view plaincopyprint?

  1. hprof-conv outofmemory0.hprof /Share/new.hprof

然后将这个导入Eclipse。MAT会给出可疑点分析,列出dominate tree,Histogram view等等,你可以看到某个对象有多少个,占用了多少内存,到底是谁一直持有它等等。是非常有用的一个工具。MAT的帮助文档写的也非常清楚,大家可以去看下。

5.常见的内存泄露

(1)持有对象不释放。

这个就是我最近碰到的一个非常典型的OOM:Activity A的onCreate()里, B b = new B(mContext);在B的构造方法里,注册了一个监听;但是在Activity A的onDestroy()并没有反注册这个监听,导致这个监听一直存在。所以这个监听一直持有mContext,从hprof文件中看,存在有7个Activiy A的实例。

换句话说,Activity A的引用并没有和A的生命周期保持一致。在A被销毁后,A的引用却依然存活。

最后的解决方法是,用application context替换了Activity context,这个也是谷歌提倡的避免OOM的一个方法。

为啥那?可能我的理解不是很到位:因为理论上application只有一个,而activity可以有多个。application context保证了在整个application的生命周期里,对application的引用只有这一个。

(2)Cursor不关闭。

这个是最常见的操作数据库导致的内存泄露。在数据量较小的并且操作次数不多的情况下,系统是没有什么特别的表现的。但是一旦数据量和操作次数变多,内存泄露就会出现。所以Cursor在使用过后一定要记得关闭。这个应该算是常识,但是在真实项目中的确会碰到由这个原因导致的问题。

(3)图片问题

(4)非静态内部类问题

(3)(4)回头更新,经验尚浅,的确没碰见过。

OOM依然是很复杂的问题,估计自己连皮毛都没搞懂,总结的这个也有很多错误,不过今后会不断更新完善。经历这次OOM,就一个感觉,一切你畏惧的东西都是纸老虎。下面几个link写的很好,留下来反复看。ps为什么人家写的技术就那么有逻辑那么清楚那?

http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html

http://kohlerm.blogspot.com/2009/07/eclipse-memory-analyzer-10-useful.html

http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html

时间: 2024-10-14 13:45:06

Android OOM(Out of memory) 内存泄露基本知识的相关文章

Android中使用Handler造成内存泄露的分析和解决

什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收:另外,如果一组对象中只包含互相的引用,而没有来自它们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这仍然属于不可到达,同样会被GC回收. Android中使用Handler造成内存泄露的原因 Handler mHand

Android性能优化:阿里、腾讯等关于内存泄露的知识都在这里了!

建议收藏,不然就找不到了!!! 前言 在 Android 中,内存泄露的现象十分常见:而内存泄露导致的后果会使得应用Crash本文 全面介绍了内存泄露的本质.原因 & 解决方案,最终提供一些常见的内存泄露分析工具,希望你们会喜欢. 目录 1. 简介 即 ML (Memory Leak)指 程序在申请内存后,当该内存不需再使用 但 却无法被释放 & 归还给 程序的现象 2. 对应用程序的影响 容易使得应用程序发生内存溢出,即 OOM内存溢出 简介: 3. 发生内存泄露的本质原因 具体描述 特

Android -> 如何避免Handler引起内存泄露

更多内容,可访问个人博客www.liangfeizc.com 错误代码 如果在Activiy中通过内部类(Runnable)的方式定义了一个变量runnable, final Runnable runnable = new Runnable() { public void run() { // ... do some work } }; handler.postDelayed(runnable, TimeUnit.SECONDS.toMillis(10) 因为Runnable不是static类型

Android中Handler引起的内存泄露

在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. 但是,其实上面的代码可能导致内存泄露,当你使用Android lint工具的话,会得到这样的警告 In Android, Handler classes should be static or leaks might occur, Messages enqueued on the application thread’s MessageQueue also retain their t

Android 中 Handler 引起的内存泄露

在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.其实这可能导致内存泄露,代码中哪里可能导致内存泄露,又是如何导致内存泄露的呢?那我们就慢慢分析一下.http://www.jinhusns.com/Products/Download/?type=xcj 在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. public class SampleActivity extends Activity {   

Android开发——Handler引起的内存泄露

在Android异步消息处理中, Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // } }; 但当我们这么写时,编译器会给出警告提示:Handler类应该是静态的,可能发生内存泄漏. 原因: 在Java中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用.静态的内部类不会持有外部类的引用. 这里Handler是一个匿名内部类的实例,其持有外面的Activity的引

JS闭包、作用域链、垃圾回收、内存泄露相关知识小结

补充: 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 闭包的三个特性: 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制回收 闭包的定义及其优缺点: 闭包 是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量 闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露. 闭包是javascript语言的一大

Android中Handler导致的内存泄露

http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html Consider the following code: 1 2 3 4 5 6 7 8 9 public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public voi

android:布局、绘制、内存泄露、响应速度、listview和bitmap、线程优化以及一些优化的建议!

1.布局优化 首先删除布局中无用的控件和层级,其次有选择地使用性能较低的viewgroup,比如布局中既可以使用RelativeLayout和LinearLayout,那我们就采用LinearLayout,因为RelativeLayout的功能比较复杂,它的布局需要花费 风度哦的CPU实际. 布局优化的另一个手段就是采用<include>,<merge>,<viewstub>标签.<include>主要用于布局重用,<include>,<m