Android OOM
MAT使用 开源框架LeakCanary http://hukai.me/android-performance-oom/
OOM
有些对象只有有限的生命周期。当它们的任务完成之后,它们将被垃圾回收。如果在对象的生命周期本该结束的时候,这个对象还被一系列的引用,这就会导致内存泄漏。随着泄漏的累积,app将消耗完内存。
比如,在Activity.onDestroy()被调用之后,view树以及相关的bitmap都应该被垃圾回收。如果一个正在运行的后台线程继续持有这个Activity的引用,那么相关的内存将不会被回收,这最终将导致OutOfMemoryError崩溃。
Android系统通过下面几种方式来实现共享内存:
Android应用的进程都是从一个叫做Zygote的进程fork出来的。Zygote进程在系统启动并且载入通用的framework的代码与资源之后开始启动。为了启动一个新的程序进程,系统会fork Zygote进程生成一个新的进程,然后在新的进程中加载并运行应用程序的代码。这使得大多数的RAM pages被用来分配给framework的代码,同时使得RAM资源能够在应用的所有进程之间进行共享。
大多数static的数据被mmapped到一个进程中。这不仅仅使得同样的数据能够在进程间进行共享,而且使得它能够在需要的时候被paged out。常见的static数据包括Dalvik Code,app resources,so文件等。
大多数情况下,Android通过显式的分配共享内存区域(例如ashmem或者gralloc)来实现动态RAM区域能够在不同进程之间进行共享的机制。例如,Window Surface在App与Screen Compositor之间使用共享的内存,Cursor Buffers在Content Provider与Clients之间共享内存。
发生OOM的条件
关于Native Heap,Dalvik Heap,Pss等内存管理机制比较复杂,这里不展开描述。简单的说,通过不同的内存分配方式(malloc/mmap/JNIEnv/etc)对不同的对象(bitmap,etc)进行操作会因为Android系统版本的差异而产生不同的行为,对Native Heap与Dalvik Heap以及OOM的判断条件都会有所影响。在2.x的系统上,我们常常可以看到Heap Size的total值明显超过了通过getMemoryClass()获取到的阈值而不会发生OOM的情况,那么针对2.x与4.x的Android系统,到底是如何判断会发生OOM呢?
Android 2.x系统 GC LOG中的dalvik allocated + external allocated + 新分配的大小 >= getMemoryClass()值的时候就会发生OOM。 例如,假设有这么一段Dalvik输出的GC LOG:GC_FOR_MALLOC free 2K, 13% free 32586K/37455K, external 8989K/10356K, paused 20ms,那么32586+8989+(新分配23975)=65550>64M时,就会发生OOM。
Android 4.x系统 Android 4.x的系统废除了external的计数器,类似bitmap的分配改到dalvik的java heap中申请,只要allocated + 新分配的内存 >= getMemoryClass()的时候就会发生OOM,如下图所示(虽然图示演示的是art运行环境,但是统计规则还是和dalvik保持一致)