Android系统内存管理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android系统内存管理相关的知识,希望对你有一定的参考价值。

参考技术A

部分内容出至林学森的android内核设计思想。
Android官网内存管理
部分出至 https://www.jianshu.com/p/94d1cd553c44

Android本质是Linux所以先从Linux说起。

Linux的内存管理为系统中所有的task提供可靠的内存分配、释放和保护机制。
核心:
虚拟内存
内存分配与释放
内存保护

将外存储器的部分空间作为内存的扩展,如从硬盘划出4GB大小。
当内存资源不足时,系统按照一定算法自动条形优先级低的数据块,并把他们存储到硬盘中。
后续如果需要用到硬盘中的这些数据块,系统将产生“缺页”指令,然后把他们交换回内存中。
这些都是由操作系统内核自动完成的,对上层应用”完全透明“。

每个进程的逻辑地址和物理地址都不是直接对应的,任何进程都没办法访问到它管辖范围外的内存空间——即刻意产生的内存越界与非法访问,操作系统也会马上阻止并强行关闭程序,从而有力的保障应用程序和操作系统的安全和稳定。

一旦发现系统的可用内存达到临界值,机会按照优先级顺序,匆匆低到高逐步杀掉进程,回收内存。
存储位置:/proc/<PID>/oom_score
优先级策略:
进程消耗的内存
进程占用的CPU时间
oom_adj(OOM权重)

Android平台运行的前提是可用内存是浪费的内存。它试图在任何时候使用所有可用的内存。例如,系统会在APP关闭后将其保存在内存中,以便用户可以快速切换回它们。出于这个原因,Android设备通常运行时只有很少的空闲内存。在重要系统进程和许多用户应用程序之间正确分配内存内对存管理是至关重要。
Android有两种主要的机制来处理低内存的情况:内核交换守护进程(kernel swap daemon)和低内存杀手(low-memory killer)。

当用户在APP之间切换时,Android会在最近使用的(LRU)缓存中保留不在前台的APP,即用户看不到的APP,或运行类似音乐播放的前台服务。如果用户稍后返回APP,系统将重用该进程,从而使APP切换更快。
如果你的APP有一个缓存进程,并且它保留了当前不需要的内存,那么即使用户不使用它,你的APP也会影响系统的整体性能。由于系统内存不足,它会从最近使用最少的进程开始杀死LRU缓存中的进程。该系统还负责处理占用最多内存的进程,并可以终止这些进程以释放RAM。
当系统开始终止LRU缓存中的进程时,它主要是自底向上工作的。系统还考虑哪些进程消耗更多的内存,从而在终止时为系统提供更多的内存增益。你在LRU列表中消耗的内存越少,你就越有可能留在列表中并能够快速恢复。

为了满足RAM的所有需求,Android尝试共享RAM来跨进程通信。它可以做到以下方式:

Android设备包含三种不同类型的内存:RAM、zRAM和storage。
注意:CPU和GPU都访问同一个RAM。

内存被拆分成页。通常每页有4KB的内存。
页面被认为是空闲的或已使用的。
空闲页是未使用的RAM。
已使用页是系统正在积极使用的RAM,分为以下类别:

干净的页面(Clean pages)包含一个文件(或文件的一部分)的一份精确副本存在存储器上。当一个干净的页面不再包含一个精确的文件副本(例如,来自应用程序操作的结果)时,它就变成了脏页。可以删除干净的页,因为它们始终可以使用存储中的数据重新生成;不能删除脏页(Dirty pages),否则数据将丢失。

内核跟踪系统中的所有内存页。

当确定一个应用程序正在使用多少内存时,系统必须考虑shared pages。APP访问相同的服务或库将可能共享内存页。例如,Google Play Services 和一个游戏APP可能共享一个位置服务。这使得很难确定有多少内存属于这个服务相对于每个APP。

当操作系统想要知道所有进程使用了多少内存时,PSS非常有用,因为页面不会被多次计数。PSS需要很长时间来计算,因为系统需要确定哪些页面是共享的,以及被有多少进程。RSS不区分共享页面和非共享页面(使计算速度更快),更适合于跟踪内存分配的更改。

内核交换守护进程(kswapd)是Linux内核的一部分,它将使用过的内存转换为空闲内存。当设备上的空闲内存不足时,守护进程将变为活动状态。Linux内核保持低和高的可用内存阈值。当空闲内存低于低阈值时,kswapd开始回收内存。当空闲内存达到高阈值,kswapd将停止回收内存。
kswapd可以通过删除干净的页面来回收干净的页面,因为它们有存储器支持并且没有被修改。如果进程试图寻址已删除的干净页,则系统会将该页从存储器复制到RAM。此操作称为请求分页。

kswapd将缓存的私有脏页(private dirty pages)和匿名脏页(anonymous dirty pages)移动到zRAM进行压缩。这样做可以释放RAM中的可用内存(空闲页)。如果进程试图触摸zRAM中脏页,则该页将被解压缩并移回RAM。如果与压缩页关联的进程被终止,则该页将从zRAM中删除。
如果可用内存量低于某个阈值,系统将开始终止进程。

lmkd实现源码要在system/core/lmkd/lmkd.c。
lmkd会创建名为lmkd的socket,节点位于/dev/socket/lmkd,该socket用于跟上层framework交互。

小结:
LMK_TARGET: AMS.updateConfiguration() 的过程中调用 updateOomLevels() 方法, 分别向/sys/module/lowmemorykiller/parameters目录下的minfree和adj节点写入相应信息;
LMK_PROCPRIO: AMS.applyOomAdjLocked() 的过程中调用 setOomAdj() 向/proc/<pid>/oom_score_adj写入oom_score_adj后直接返回;
LMK_PROCREMOVE: AMS.handleAppDiedLocked 或者 AMS.cleanUpApplicationRecordLocked() 的过程,调用remove(),目前不做任何事,直接返回;

为了进一步帮助平衡系统内存并避免终止APP进程,可以Activity类中实现ComponentCallbacks2接口。提供的onTrimMemory()回调方法允许APP在前台或后台侦听与内存相关的事件,然后释放对象以响应应用程序生命周期或表明系统需要回收内存的系统事件。
onTrimMemory()回调是在Android 4.0(API级别14)中添加的。
对于早期版本,可以使用onLowMemory(),它大致相当于TRIM_MEMORY_COMPLETE事件。

一个专门的驱动。(Linux Kernel 4.12 已移除交给kswapd处理)。
很多时候,kswapd无法为系统释放足够的内存。在这种情况下,系统使用onTrimMemory()通知APP内存不足,应该减少其分配。如果这还不够,内核将开始终止进程以释放内存,它使用低内存杀手(LMK)来完成这个任务。
为了决定要终止哪个进程,LMK使用一个名为oom_adj_score的“out of memory”分数来确定运行进程的优先级,高分的进程首先被终止。
后台应用程序首先被终止,系统进程最后被终止。
下表列出了从高到低的LMK评分类别。第一排得分最高的项目将首先被杀死:

Android Runtime(ART)和Dalvik虚拟机使用分页(Paging)和内存映射(mmapping)来管理内存。应用程序通过分配新对象或触摸已映射页面来修改内存都将保留在RAM中,并且不能被调出。应用程序释放内存的唯一方式是垃圾收集器。

Android中的内存管理

1.内存管理机制概述

1.分配机制:

安卓系统会为每个进程合理的分配内存,从而保证每个进程能正常运行。而不至于内存不够使用或者每个进程占用太多的内存。

2.回收机制

操作系统在内存不足的时候,它会有一个合理的回收和再分配的机制。

从而保证新的进程能够正常运行。回收的时候就可能杀死那些正在占用内存的进程。所以操作系统需要有一个合理的杀死占用内存的进程的机制,以保证把副作用降到最低。

二。安卓内存管理机制

1.分配机制

安卓采用弹性内存分配机制。也就是说一开始并不会分配太多的内存。而是给每一个APP的进程分配一个小额的量。这个小额的量跟手机的内存大小有关。

当进程内存不够的时候,安卓会再分配一些内存给各个进程。但是这个内存大小不是随意的,他是有限度的。操作系统也想让更多的进程存活。这样用户打开进程的时候不用重新创建,只用恢复就行。

2.回收机制

安卓对于进程的分类是有优先级的。对进程进行了分类,主要分为这样5大类。

1.前台进程

也就是在屏幕当前显示的进程

2.可见进程

可见进程也就是说,前台进程他已经不再属于前台了。但是用户仍能看到的进程。

3.服务进程

开启一些服务,比如推送,定位等等。

4.后台进程

后台进程不同于服务进程。他会在后台进行一些计算。

5.空进程

没有任何东西在运行的进程。内存可以随时把他回收掉。

那么安卓为什么要搞这个分级呢?因为级别越低,被系统杀死回收的可能性越大。

这里我们注意,前台进程,可见进程,服务进程,正常情况下他是绝对不会被杀死和回收的。

而后台进程存到一个缓存列表中,这个缓存列表是LRU结构,也就是最近最少使用。

而空进程是为了平衡整个系统性。安卓不会保存这个进程。

安卓在开始杀死进程的时候,系统会判断杀死这个进程所带来的效益。

安卓总是更倾向于杀死能回收更多内存的进程。

三。内存管理机制的特点

我们可以理解为系统的内存管理目标

1、占用更少的内存

2、在合适的时候,合理的释放内存资源。

3.在系统内存紧张的情况下,能释放掉大部分不重要的资源。来为android系统提供可用的内存。

4.能够很合理的在特殊生命周期中,保存或者还原重要数据,以至于系统能够正确的重新恢复该应用。

四。内存优化的方法

1.当service完成后,尽量停止他。

可以用intentservice代替service。

因为intentservice可以在intenthandler方法中执行耗时任务,而且在运行完成后,会自动退出。

2.在UI不可见的时候,释放掉一些只有UI使用的资源。

3.在系统内存紧张的时候,尽可能多的释放掉一些非重要的资源。

4.避免滥用Bitmap造成的内存浪费。

5.使用针对内存优化过的数据容器。

6.避免使用依赖注入的框架。

7.使用zip对齐的APK

8.使用多进程。

以上是关于Android系统内存管理的主要内容,如果未能解决你的问题,请参考以下文章

:Android系统的安全机制

细读《深入理解 Android 内核设计思想》内存管理

细读《深入理解 Android 内核设计思想》内存管理

Android 内存管理机制详解

(转)Android进程管理详解

Android内存解析—从Linux系统内存逐步认识Android应用内存