Android 内存管理

Android系统是基于Linux 2.6内核开发的开源操作系统,而linux系统的内存管理有其独特的动态存储管理机制。
不过Android系统对Linux的内存管理机制进行了优化,Linux系统会在进程活动停止后就结束该进程,而Android把这些进程都保留在内存中,直到系统需要更多内存为止。这些保留在内存中的进程通常情况下不会影响整体系统的运行速度,并且当用户再次激活这些进程时,提升了进程的启动速度。

Android内存管理包含两部分,一部分是Framework对内存的管理一部分是Linux内核对内存管理,这两部分共同决定应用程序的生命周期。

在Android中,大部分应用程序都运行在一个独立的Linux进程中,每个进程都有独立的内存空间。随着各种应用程序启动,系统内存不断下降,为了保证新应用能够运行,Android需要一套机制杀死暂时闲置的进程。

Android Framework并不能直接回收内存,其管理进程的服务(ActivityManagerService,以下简称AmS)也同应用程序一样运行在Java虚拟机环境里。Java虚拟机都运行在各自独立的内存空间,所以ActivityManagerService没有办法感知应用程序是否OOM。

Android系统中还运行了一个OOM进程。该进程启动时首先会在Linux内核中把自己注册为一个OOM Killer。AmS需要把每一个应用程序的oom_adj值告知OOM Killer,这个值的范围在-16到15之间,值越低,说明越重要,这个值类似于Linux中的nice值,只在标准的Linux中,有其自己的OOM Killer。Android中的OOM Killer进程仅仅适用于Android应用程序。

当内核的内存管理模块检测到系统内存不足时就会通知OOM Killer,然后OOM Killer根据AmS所告知的优先级强制退出优先级低的应用程序。

Android 内存管理机制

基于Linux内核OOM Killer的核心思想,Android 系统扩展出了自己的内存监控体系。因为Linux下的内存杀手需要等到系统资源”濒临绝境”的情况下才会产生效果。
而Android则实现了自己的Killer。Android 系统为此开发了一个专门的驱动,名为Low Memory Killer(LMK)。源码路径在内核工程的drivers/staging/android/Lowmemorykiller.c中。

它的驱动加载函数如下:

static int __init lowmem_init(void)
{
    register_shrinker(&lowmem_shrinker);
    return 0;
}

当系统的空闲页面低于一定阈值时,这个回调就会被执行。

Lowmemorykiller.c 中定义了两个数组,分别如下:

static short lowmem_adj[6] = {
    0,
    1,
    6,
   12,
 };
static int lowmem_adj_size = 4;//下面的数值以此为单位(页大小)
static int lowmem_minfree[6] = {
    3 * 512,    /* 6MB */
    2 * 1024,   /* 8MB */
    4 * 1024,   /* 16MB */
    16 * 1024,  /* 64MB */
};
  • 第一个数组lowmem_adj最多有6个元素,默认只定义了4个,它表示可用容量处于”某层级”时需要被处理的adj值;

  • 第二个数组则是对”层级”的描述。举个例子,lowmem_minfree 的第一个元素是3*512*lowmem_adj_size=6MB,意味着当可用内存小于6MB时,Killer需要清理adj的值为0(即lowmem_adj的第一个元素)以下的那些进程。其中adj的取值范围是-17~15,数字越小表示进程级别越高,通常只有0-15被使用。

android进程优先级

android将进程的优先级分为5个层次,按照优先级由高到低排列如下:

  1. 前台进程(Foreground process):它表明用户正在与该进程进行交互操作,android系统依据下面的条件来将一个进程标记为前台进程:
  • 该进程持有一个用户正在与其交互的Activity(也就是这个activity的生命周期方法走到了onResume()方法)。
  • 该进程持有一个Service,并且这个Service与一个用户正在交互中的Activity进行绑定。
  • 该进程持有一个前台运行模式的Service(也就是这个Service调用了startForegroud()方法)。
  • 该进程持有一个正在执行生命周期方法(onCreate()、onStart()、onDestroy()等)的Service。
  • 该进程持有一个正在执行onReceive()方法的BroadcastReceiver。
    一般情况下,不会有太多的前台进程。杀死前台进程是操作系统最后无可奈何的做法。当内存严重不足的时候,前台进程一样会被杀死。
  1. 可见进程(Visible process):它表明虽然该进程没有持有任何前台组件,但是它还是能够影响到用户看得到的界面。android系统依据下面的条件将一个进程标记为可见进程:
  • 该进程持有一个非前台Activity,但这个Activity依然能被用户看到(也就是这个Activity调用了onPause()方法)。例如,当一个activity启动了一个对话框,这个activity就被对话框挡在后面。
  • 该进程持有一个与可见(或者前台)Activity绑定的Service。
  1. 服务进程(Service process):除了符合前台进程和可见进程条件的Service,其它的Service都会被归类为服务进程。

  2. 后台进程(Background process):持有不可见Activity(调用了onStop()方法)的进程即为后台进程。通常情况下都会有很多后台进程,当内存不足的时候,在所有的后台进程里面,会按照LRU(最近使用)规则,优先回收最长时间没有使用过的进程。

  3. 空进程(Empty process):不持有任何活动组件的进程。保持这种进程只有一个目的,就是为了缓存,以便下一次启动该进程中的组件时能够更快响应。当资源紧张的时候,系统会平衡进程缓存和底层的内核缓存情况进行回收。

前台>可见>服务>后台>空

如果一个进程同时满足上述5种优先级中的多个等级条件,android系统会优先选取其中最高的等级作为该进程的优先级。

内存管理机制的特点

  1. 更少的占用内存;
  2. 在合理的时候,合理的释放内存;
  3. 在系统内存紧张的情况下,能释放大部分不重要的的资源,来为Android提供可用的资源;
  4. 能够很合理的在特殊生命周期中,保存和回复还原重要数据,以至于系统能够正确的重新恢复该应用。

一些内存优化的方法

  1. 当Service完成任务后,尽量停止它,或者用intentService代替;
  2. 在UI不可见的时候,释放掉一些只有UI使用的资源;
  3. 在系统资源内存紧张的时候,尽可能多的释放掉一些非重要资源;
  4. 避免滥用Bitmap导致的内存浪费,参见Here
  5. 使用针对内存优化过的数据容器
  6. 避免使用依赖注入的框架
  7. 使用ZIP对其APK
  8. 使用多进程

参考并感谢

  1. Android内存管理机制详解
  2. Android 内存管理机制详解
  3. Android 内存优化总结&实践
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • Android是一个基于Linux实现的操作系统。但对于Linux内核来说,Android也仅仅只是一个运行在内核...
    Gooooood阅读 3,401评论 1 15
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,463评论 25 707
  • 一.操作系统相关基础知识 1.物理内存、虚拟内存、逻辑地址与交换空间 物理内存(RAM):加载到内存地址寄存器中的...
    Geeks_Liu阅读 9,121评论 6 30
  • 先看看百度 1842年,英国物理学家Earnshaw就提出了磁悬浮的概念,同时指出:单靠永久磁铁是不能将一个铁磁体...
    我要去拉萨阅读 808评论 0 1
  • 从朕登基,最讨厌的就是做周报。一周五天,周一开会,周五做周报。朕哪还有时间处理政事,宠幸爱妃。 直到用了matpl...
    胖兔123阅读 963评论 0 0