[Android Memory] Android内存管理、监测剖析

时间:2024-01-03 13:01:56

转载自:http://blog.csdn.net/anlegor/article/details/23398785

Android内存管理机制:

Android内存管理主要有:LowMemory Killer机制,Ashmem,PMEM/ION及Native内存和Dalvik内存管理管理和JVM垃圾回收机制。

LowMemory Killer机制:

源码位置drivers/staging/Android/lowmemorykiller.c

Android是一个多任务系统,也就是说可以同时运行多个程序,这个大家应该很熟悉。一般来说,启动运行一个程序是有一定的时间开销的,因此为了加快运行速度,当你退出一个程序时,Android并不会立即杀掉它,这样下次再运行该程序时,可以很快的启动。随着系统中保留的程序越来越多,内存肯定会出现不足,low memory killer就是在系统内存低于某值时,清除相关的程序,保障系统保持拥有一定数量的空闲内存。

Low memorykiller根据两个原则,进程的重要性和释放这个进程可获取的空闲内存数量,来决定释放的进程。

进程的重要性,由task_struct->signal_struct->oom_adj决定,

Android将程序的重要性分成以下几类,按照重要性依次降低的顺序,每个程序都会有一个oom_adj值,这个值越小,程序越重要,被杀的可能性越低:

[Android Memory]   Android内存管理、监测剖析

除了上述程序重要性分类之外,Android系统还维护着另外一张表minfree用于维护内存警戒值,这两张表构成一个对应关系,两张表在” /sys/module/lowmemorykiller/parameters/”下保存。

[Android Memory]   Android内存管理、监测剖析

adj文件内容如下形如”0,1,2,4,9,15”,minfree文件内容形如”8192,10240,12288,14336,1638,20480”,这样形成的表结构如下:

[Android Memory]   Android内存管理、监测剖析

例如,当系统可用内存小于12384*4K大小时,会开始杀掉oom_adj>=9级别的进程。

进程的内存,通过get_mm_rss获取,在相同的oom_adj下,内存大的,优先被杀。

Ashmem(匿名内存共享):

源码位置:kernel/mm/ashmem.c

为进程间提供提供大块共享内存,同时为内核提供回收和管理这个内存的机制。

相比于malloc和anonymous/namedmmap等传统的内存分配机制,其优势是通过内核驱动提供了辅助内核的内存回收算法机制(pin/unpin)。什么是pin和unpin呢?具体来讲,就是当你使用Ashmem分配了一块内存,但是其中某些部分却不会被使用时,那么就可以将这块内存unpin掉。

unpin后,内核可以将它对应的物理页面回收,以作他用。你也不用担心进程无法对unpin掉的内存进行再次访问,因为回收后的内存还可以再次被获得(通过缺页handler),因为unpin操作并不会改变已经 mmap的地址空间。

AndroidPMEM/ION内存管理器:

源码位置:drivers/misc/pmem.c

AndroidPmem是为了实现共享大尺寸连续物理内存而开发的一种机制,该机制对dsp,gpu等部件非常有用。Pmem相当于把系统内存划分出一部分单独管理,即不被linux mm管理,实际上linux mm根本看不到这段内存。

Pmem和Ashmem都通过mmap来实现共享内存,其区别在于Pmem的共享区域是一段连续的物理内存,而Ashmem的共享区域在虚拟空间是连续的,物理内存却不一定连续。dsp和某些设备只能工作在连续的物理内存上,这样cpu与dsp之间的通信就需要通过Pmem来实现。

ION是google在Android4.0ICS为了解决内存碎片管理而引入的通用内存管理器,它会更加融合kernel。目前QCOM MSM, NVDIA Tegra, TI OMAP, MRVL PXA都用ION替换PMEM。

ION 定义了四种不同的heap,实现不同的内存分配策略。

[Android Memory]   Android内存管理、监测剖析

AndroidNative内存和Dalvik内存管理:

Native进程是采用C/C++实现,不包含dalvik实例的进程,/system/bin/目录下面的程序文件运行后都是以native进程形式存在的,如/system/bin/surfaceflinger、/system/bin/rild、procrank等就是native进程,地址空间结构如下:

[Android Memory]   Android内存管理、监测剖析

java进程是Android中运行于dalvik虚拟机之上的进程。dalvik虚拟机的宿主进程由fork()系统调用创建,所以每一个java进程都是存在于一个native进程中,因此,java进程的内存分配比native进程复杂,因为进程中存在一个虚拟机实例。Android系统中的应用程序基本都是java进程,如桌面、电话、联系人、状态栏等等,进程结构如下:

[Android Memory]   Android内存管理、监测剖析

Stack空间(进栈和出栈)由操作系统控制,其中主要存储函数地址、函数参数、局部变量等等,所以Stack空间不需要很大,一般为几MB大小。

Heap空间的使用由程序员控制,程序员可以使用malloc、new、free、delete等函数调用来操作这片地址空间。Heap为程序完成各种复杂任务提供内存空间,所以空间比较大,一般为几百MB到几GB。正是因为Heap空间由程序员管理,所以容易出现使用不当导致严重问题。

进程空间中的heap空间是我们需要重点关注的。heap空间完全由程序员控制,我们使用的malloc、C++ new和java new所申请的空间都是heap空间, C/C++申请的内存空间在native heap中,而java申请的内存空间则在dalvik heap中。

进程的内存空间只是虚拟内存(或者叫作逻辑内存),而程序的运行需要的是实实在在的内存,即物理内存(RAM)。在必要时,操作系统会将程序运行中申请的内存(虚拟内存)映射到RAM,让进程能够使用物理内存。

RAM作为进程运行不可或缺的资源,对系统性能和稳定性有着决定性影响。另外,RAM的一部分被操作系统留作他用,比如显存等等,内存映射和显存等都是由操作系统控制,我们也不必过多地关注它,进程所操作的空间都是虚拟地址空间,无法直接操作RAM。示意图如下:

[Android Memory]   Android内存管理、监测剖析

Android系统对dalvik的vm heapsize作了硬性限制,当java进程申请的java空间超过阈值时,就会抛出OOM异常,在/system/build.prop中有三项可以配置相关信息。

dalvik.vm.heapstartsize:堆分配的初始大小,调整这个值会影响到应用的流畅性和整体ram消耗。这个值越小,系统ram消耗越慢,但是由于初始值较小,一些较大的应用需要扩张这个堆,从而引发gc和堆调整的策略,会应用反应更慢。相反,这个值越大系统ram消耗越快,但是程序更流畅。

dalvik.vm.heapgrowthlimit:受控情况下的极限堆(仅仅针对dalvik堆,不包括native堆)大小,dvm heap是可增长的,但是正常情况下dvm heap的大小是不会超过dalvik.vm.heapgrowthlimit的值(非正常情况下面会详细说明)。这个值控制那些受控应用的极限堆大小,如果受控的应用dvm heap size超过该值,则将引发oom(out of memory)。

dalvik.vm.heapsize:不受控情况下的极限堆大小,这个就是堆的最大值。不管它是不是受控的。这个值会影响非受控应用的dalvikheap size。一旦dalvik heap size超过这个值,直接引发oom。

JVM垃圾回收机制:

[Android Memory]   Android内存管理、监测剖析

JVM的垃圾原理是这样的,它把对象分为年轻代(Young)、年老代(Tenured)、持久代(Perm),对不同生命周期的对象使用不同的垃圾回收算法。

年轻代(Young):年轻代分为三个区,一个eden区,两个Survivor区。程序中生成的大部分新的对象都在Eden区中,当Eden区满时,还存活的对象将被复制到其中一个Survivor区,当此Survivor区的对象占用空间满了时,此区存活的对象又被复制到另外一个Survivor区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制到年老代。

年老代(Tenured)年老代存放的是上面年轻代复制过来的对象,也就是在年轻代中还存活的对象,并且区满了复制过来的。一般来说,年老代中的对象生命周期都比较长。

持久代(Perm)用于存放静态的类和方法,持久代对垃圾回收没有显著的影响。

Android内存分析工具:

         内存监控工具DDMS:

Ddms可以在eclipse中安装对应的插件,同时在androidsdk的tools文件夹也有同样的工具,并且功能比eclipse插件更完备。

切换到eclipse的ddms视图后,从设备中选择要监控的进程(手机需要开启usb调试,被监控应用的manifest中android:debuggable应该为true)

如下图操作,我们主要关注dataobject类型的total size数据在使用过程中是否出现异常的数据波动。

[Android Memory]   Android内存管理、监测剖析

Eclipse MAT插件:

Mat是eclipse的一个插件,安装完成之后,在ddms试图下,同时在左侧设备试图上方选择“Update Heap”和“Dump HPROF file”按钮,在弹出的窗口中选择“Leak Suspects Report”并finish,即可出现下面的结果试图:

[Android Memory]   Android内存管理、监测剖析

进入leaksuspects之后,就能列出所有可能有泄漏的地方以及代码片段

[Android Memory]   Android内存管理、监测剖析

Adb shell的dumpsys meminfo命令:

[Android Memory]   Android内存管理、监测剖析

Adbshell的cat命令:

[Android Memory]   Android内存管理、监测剖析

应用内存分配跟踪工具Allocation tracker:

同样该功能用到ddms ,只是里面提供的一个子功能而已,能够知道所有对象的分配是在代码的哪个类,哪个文件的哪一行。

[Android Memory]   Android内存管理、监测剖析

AndroidOOM的常见原因:

非静态内部类的静态实例容易造成内存泄漏

activity使用静态成员

使用handler时的内存问题

注册某个对象后未反注册

集合中对象没清理造成的内存泄露

资源对象没关闭造成的内存泄露

一些不良代码成内存压力:Bitmap使用不当;构造Adapter时,没有使用缓存的 convertView;在经常调用的方法中创建对象(例如循环)

参考资料:

Androidmemory fundamentals

http://www.slideshare.net/tarasleskiv/android-memory-fundamentals?qid=c8462372-7470-4459-a76c-552c678724c0&v=qf1&b=&from_search=2

Forensic Memory Analysis of Android'sDalvik Virtual Machine

http://www.slideshare.net/SOURCEConference/forensic-memory-analysis-of-androids-dalvik-virtual-machine?qid=c8462372-7470-4459-a76c-552c678724c0&v=qf1&b=&from_search=6

Memory management for_android_apps

http://www.slideshare.net/shaobin0604/memory-management-forandroidapps?qid=c8462372-7470-4459-a76c-552c678724c0&v=qf1&b=&from_search=11

android内存管理机制分析

http://www.doc88.com/p-992213371842.html

Android 操作系统的内存回收机制

http://blog.jobbole.com/25169/

Android系统匿名共享内存(AnonymousShared Memory)C++调用接口分析

http://blog.csdn.net/luoshengyang/article/details/6939890

Android系统匿名共享内存Ashmem(AnonymousShared Memory)简要介绍和学习计划 - 老罗的Android之旅 - 博客频道 - CSDN.NET

http://blog.csdn.net/luoshengyang/article/details/6651971

程序源代码分析 - 老罗的Android之旅 - 博客频道 - CSDN.NET

http://blog.csdn.net/luoshengyang/article/details/6664554

Android系统匿名共享内存Ashmem(AnonymousShared Memory)在进程间共享的原理分析 - 老罗的Android之旅 - 博客频道 - CSDN.NET

http://blog.csdn.net/luoshengyang/article/details/6666491

Windows内存与进程管理器底层分析

http://www.cnblogs.com/zudn/archive/2010/12/29/1920593.html

什么是内存直接映像技术?它有何特点?

http://zhidao.baidu.com/link?url=e8NFxuOaY9UsOxKGklWmTR20-gpDGy48eE1SerGNCjAYbg3Xj-Fp0pqBSAKFy_AEjyKQOWmx3QHGn4ldWgec0M1wxBowDOT59Bua2O0DjZC

Mysteries of Windows Memory ManagementRevealed

http://media.ch9.ms/teched/na/2011/ppt/WCL406.pptx

全面介绍Windows内存管理机制及C++内存分配实例

http://blog.csdn.net/yeming81/article/details/2046193

技术内幕:Android对Linux内核的增强

http://tech.it168.com/a2011/0805/1228/000001228471_all.shtml

android内存管理了解_百度文库

http://wenku.baidu.com/link?url=bGaPQbl7u1_JmKSJ5nVBv1dHtvGSXREyv_7PeSt9_FCx20I5oK1EaEgno9d6Ked4Kao92yoP_7X6gOQToylezMwEn-inKnBxb7SAoJ3jH6m

Android low memory killer 详解-tuyer-ChinaUnix博客

http://blog.chinaunix.net/uid-20321537-id-3228776.html

Linux 设备文件简介

http://www.jinbuguo.com/kernel/device_files.html

Explore Android Internals

http://www.slideshare.net/jserv/android-internals-30176596?qid=a3be858d-e483-423c-be0e-a85e0a08fdd6&v=qf1&b=&from_search=4

Inside Android's Dalvik VM - NEJUG Nov 2011

http://www.slideshare.net/dougqh/inside-androids-dalvik-vm-nejug-nov-2011?qid=a3be858d-e483-423c-be0e-a85e0a08fdd6&v=qf1&b=&from_search=3

android之ION内存管理器(1)-- 简介

http://blog.csdn.net/crazyjiang/article/details/7927260

Android进程的内存管理分析

http://blog.csdn.net/gemmem/article/details/8920039

Gc in android

http://www.slideshare.net/VikasBalikai/gc-in-android

Android内存泄漏分析及调试

http://blog.csdn.net/gemmem/article/details/13017999

Android OOM介绍及分析方法

http://blog.csdn.net/gemmem/article/details/8964397