进程间的内存分配

进程间的内存分配

Android 平台运行的前提是:空闲内存即浪费的内存。它始终尝试使用所有可用内存。例如,系统会在应用关闭后将其保留在内存中,以便用户可以快速切换回这些应用。因此,Android 设备运行时的剩余可用内存通常很少。内存管理对于在重要的系统进程和许多用户应用之间合理分配内存至关重要。

本页面讨论了 Android 如何为系统和用户应用分配内存的基础知识。它还解释了操作系统如何应对内存不足的情况。

内存类型

Android 设备包含三种不同类型的内存:RAM、zRAM 和存储空间。请注意,CPU 和 GPU 访问的是同一块 RAM。

图 1. 内存类型 - RAM、zRAM 和存储空间

RAM 是最快的内存类型,但容量通常有限。高端设备通常拥有最大的 RAM 容量。

zRAM 是 RAM 的一个分区,用作交换空间。所有数据在放入 zRAM 时都会被压缩,在从 zRAM 取出时会被解压缩。随着页面被移入或移出 zRAM,这部分 RAM 的大小会增加或减小。设备制造商可以设置其最大容量。

存储空间包含所有持久性数据,例如文件系统以及所有应用、库和平台的内置目标代码。存储空间的容量比其他两种内存类型大得多。在 Android 上,存储空间不像其他 Linux 实现那样用作交换空间,因为频繁写入会磨损存储介质,从而缩短其使用寿命。

内存页面

RAM 被划分为页面。通常每个页面为 4KB 内存。

页面分为空闲或已使用。空闲页面是未使用的 RAM。已使用页面是系统正在积极使用的 RAM,分为以下几类:

缓存 (Cached):由存储空间上的文件支持的内存(例如代码或内存映射文件)。缓存内存有两种类型:

私有 (Private):由一个进程拥有且不共享。

干净 (Clean):存储空间上文件的未修改副本,可由 kswapd 删除以增加空闲内存。

脏 (Dirty):存储空间上文件的已修改副本;可由 kswapd 移动到 zRAM 或在其中压缩,以增加空闲内存。

共享 (Shared):由多个进程使用。

干净 (Clean):存储空间上文件的未修改副本,可由 kswapd 删除以增加空闲内存。

脏 (Dirty):存储空间上文件的已修改副本;允许更改写回存储空间中的文件,从而由 kswapd 增加空闲内存,或者通过显式使用 msync() 或 munmap() 来增加空闲内存。

匿名 (Anonymous):不由存储空间上的文件支持的内存(例如,通过设置了 MAP_ANONYMOUS 标志的 mmap() 分配的内存)。

脏 (Dirty):可由 kswapd 移动到 zRAM 或在其中压缩,以增加空闲内存。

注意:干净页面包含存储空间中存在的文件的精确副本(或文件的一部分)。当页面不再包含文件的精确副本时(例如,由于应用操作的结果),干净页面就会变成脏页面。干净页面可以被删除,因为它们总是可以使用来自存储空间的数据重新生成;脏页面不能被删除,否则会导致数据丢失。

随着系统积极管理 RAM,空闲和已使用页面的比例会随时间发生变化。本节介绍的概念对于管理内存不足的情况至关重要。本文档的下一节将对此进行更详细的解释。

内存不足管理

Android 有两种主要机制来处理内存不足的情况:内核交换守护进程和低内存终止守护进程。

内核交换守护进程

内核交换守护进程 (kswapd) 是 Linux 内核的一部分,它将已使用的内存转换为可用内存。当设备上的可用内存不足时,该守护进程会被激活。Linux 内核维护着空闲内存的低阈值和高阈值。当空闲内存低于低阈值时,kswapd 开始回收内存。一旦空闲内存达到高阈值,kswapd 就会停止回收内存。

kswapd 可以通过删除干净页面来回收它们,因为它们由存储空间支持且未被修改。如果进程尝试访问已删除的干净页面,系统会将该页面从存储空间复制到 RAM。此操作称为请求分页 (demand paging)。

图 2. 由存储空间支持的干净页面被删除

kswapd 可以将缓存的私有脏页面和匿名脏页面移动到 zRAM,在其中进行压缩。这样做可以释放 RAM 中的可用内存(空闲页面)。如果进程尝试访问 zRAM 中的脏页面,该页面会被解压缩并移回 RAM。如果与已压缩页面关联的进程被终止,则该页面会从 zRAM 中删除。

如果可用内存量低于特定阈值,系统将开始终止进程。

图 3. 脏页面被移至 zRAM 并压缩

低内存终止守护进程

很多时候,kswapd 无法为系统释放足够的内存。在这种情况下,系统会使用 onTrimMemory() 通知应用内存不足,并应减少其分配。如果这还不够,内核会开始终止进程以释放内存。它使用低内存终止守护进程 (LMK) 来执行此操作。

为了决定终止哪个进程,LMK 使用名为 oom_adj_score 的“内存不足”得分来对运行中的进程进行优先级排序。得分高的进程会被优先终止。后台应用会首先被终止,系统进程最后被终止。下表按从高到低的顺序列出了 LMK 得分类别。第一行中得分最高的类别的项目将首先被终止。

图 4. Android 进程,得分最高的在顶部,得分最低的在底部

以下是上表中各分类的描述:

后台应用:之前运行过但当前未激活的应用。LMK 将首先终止后台应用,从 oom_adj_score 最高的应用开始。

上一个应用:最近使用的后台应用。上一个应用比后台应用具有更高的优先级(得分更低),因为用户切换到它的可能性比切换到后台应用的可能性更大。

主屏幕应用:这是启动器应用。终止它会导致壁纸消失。

服务:由应用启动的服务,可能包括同步或上传到云端。

可感知的应用:非前台应用,但在某种程度上对用户可见,例如运行显示小 UI 的搜索进程或听音乐。

前台应用:当前正在使用的应用。终止前台应用看起来就像应用崩溃,这可能会向用户表明设备出现了问题。

持久性(服务):这些是设备的核心服务,例如电话和 Wi-Fi。

系统:系统进程。当这些进程被终止时,手机可能会看起来像重启了一样。

原生:系统使用的极底层进程(例如 kswapd)。

设备制造商可以更改 LMK 的行为。

计算内存占用量

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

图 5. 不同进程使用的页面

在确定应用使用了多少内存时,系统必须考虑共享页面。访问相同服务或库的应用将共享内存页面。例如,Google Play 服务和游戏应用可能会共享一个定位服务。这使得确定有多少内存属于该服务本身与属于每个应用变得困难。

图 6. 两个应用共享的页面(中间)

要确定应用的内存占用量,可以使用以下任何指标:

驻留集大小 (RSS):应用使用的共享和非共享页面的数量。

比例集大小 (PSS):应用使用的非共享页面的数量加上共享页面的均匀分布(例如,如果三个进程共享 3MB,则每个进程在 PSS 中获得 1MB)。

唯一集大小 (USS):应用使用的非共享页面的数量(不包含共享页面)。

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

其他资源

内存管理概览

进程与应用生命周期

了解 Android 内存使用 - Google I/O 演讲

Android 内存与游戏 - Google I/O 演讲

Android 低内存终止守护进程

为您推荐

注意:当 JavaScript 关闭时,会显示链接文本

应用启动时间

🎭 相关推荐 🎭

华山旅游攻略: 一份超全超具体的游玩指南
绝地求生6月26日维护到几点 6.26维护结束时间
足智多谋的解释及意思
365下载bet

足智多谋的解释及意思

📅 08-22 👀 6517