低内存配置

原文:https://source.android.com/devices/tech/perf/low-ram

介绍

Android现在支持512MB RAM的设备。本文旨在帮助OEM为低内存设备优化和配置Android 4.4。其中一些优化非常通用,它们也可以应用于以前的版本。

Android 4.4平台优化

改进了内存管理

  • 验证的内存节省内核配置:交换到ZRAM。
  • 如果要缓存且太大,则终止缓存进程。
  • 不允许大型服务将自己放回A服务中(因此它们不会导致启动器被终止)。
  • 终止在空闲维护中过大的进程(即使是通常不可用的,例如当前的IME)。
  • 序列化后台服务的启动。
  • 调整低RAM设备的内存使用:更严格的内存不足(OOM)调整级别,更小的图形缓存等。

减少系统内存

  • 裁剪system_server和SystemUI进程(节省几MB)。
  • 在Dalvik中预加载dex缓存(节省几MB)。
  • 验证JIT-off选项(每个进程最多可节省1.5MB)。
  • 减少每进程字体缓存开销。
  • 引入ArrayMap / ArraySet并在Framework中广泛使用,作为HashMap / HashSet的轻量级替代品。

进程统计

添加新的开发者选项,用于显示内存状态和应用程序内存使用情况,并根据运行频率和内存消耗量进行排序。

API

添加新的ActivityManager.isLowRamDevice(),用于允许应用程序检测何时在低内存设备上运行并选择禁用大RAM功能。

内存跟踪

新memtrack HAL用于跟踪图形内存分配,dumpsys meminfo中的附加信息,meminfo中的概要说明(例如报告的可用RAM包括缓存进程的RAM,以便OEM不会尝试优化错误的东西)。

构建时配置

启用低Ram设备标志

我们正在引入一个名为ActivityManager.isLowRamDevice()的新API ,以便应用程序确定是否应该关闭在低内存设备上运行不佳的特定内存密集型功能。

对于512MB设备,此API有望返回true。它可以通过设备makefile中的以下系统属性启用。

PRODUCT_PROPERTY_OVERRIDES + = ro.config.low_ram = true

Launcher配置

确保Launcher上的默认壁纸设置 使用动态壁纸。低内存设备不应预安装任何动态壁纸。

内核配置

调整内核/ActivityManager以减少直接回收

当进程或内核尝试分配一页内存(直接或由于新页面中的错误)并且内核已使用所有可用空闲内存时,会发生直接回收。这要求内核在释放页面时阻止分配。相反,这经常需要磁盘I/O清除垃圾文件(备份页面)或等待lowmemorykiller终止进程。这可能导致任何线程中的额外I/O,包括UI线程。

为避免直接回收,内核具有触发kswapd或后台回收的水印。这是一个试图释放页面的线程,因此下一次真正的线程分配它可以快速成功。

触发后台回收的默认阈值相当低,2GB设备上约为2MB,512MB设备上为636KB。并且内核回收在后台只回收了几MB的内存。这意味着快速分配超过几兆字节的任何进程都将很快导致直接回收。

android-3.4内核分支中添加了对新内核可调参数的支持,见补丁92189d47f66c67e5fd92eafaa287e153197a454f(“添加额外的空闲kbytes可调”)。将此补丁合入到设备的内核将允许ActivityManager告诉内核尝试保留3个全屏32 bpp内存缓冲区。

可以通过框架config.xml配置这些阈值

<!-- Device configuration setting the /proc/sys/vm/extra_free_kbytes tunable
in the kernel (if it exists).  A high value will increase the amount of memory
that the kernel tries to keep free, reducing allocation time and causing the
lowmemorykiller to kill earlier.  A low value allows more memory to be used by
processes but may cause more allocations to block waiting on disk I/O or
lowmemorykiller.  Overrides the default value chosen by ActivityManager based
on screen size.  0 prevents keeping any extra memory over what the kernel keeps
by default.  -1 keeps the default. -->
<integer name="config_extraFreeKbytesAbsolute">-1</integer>

<!-- Device configuration adjusting the /proc/sys/vm/extra_free_kbytes
tunable in the kernel (if it exists).  0 uses the default value chosen by
ActivityManager.  A positive value  will increase the amount of memory that the
kernel tries to keep free, reducing allocation time and causing the
lowmemorykiller to kill earlier.  A negative value allows more memory to be
used by processes but may cause more allocations to block waiting on disk I/O
or lowmemorykiller.  Directly added to the default value chosen by
ActivityManager based on screen size. -->
<integer name="config_extraFreeKbytesAdjust">0</integer>

调整LowMemoryKiller

ActivityManager配置LowMemoryKiller的阈值,以匹配在每个优先级存储桶中运行进程所需的文件(支持页面(缓存页面))的工作集的期望。如果设备对工作集具有高要求,例如,如果厂商UI需要更多内存或者如果添加了更多服务,则可以增加阈值。

如果为文件支持的页面保留了太多内存,则可以减少阈值,因此在因缓存变得太小而导致磁盘抖动发生之前后台进程将会被长时间终止。

<!-- Device configuration setting the minfree tunable in the lowmemorykiller
in the kernel.  A high value will cause the lowmemorykiller to fire earlier,
keeping more memory in the file cache and preventing I/O thrashing, but
allowing fewer processes to stay in memory.  A low value will keep more
processes in memory but may cause thrashing if set too low.  Overrides the
default value chosen by ActivityManager based on screen size and total memory
for the largest lowmemorykiller bucket, and scaled proportionally to the
smaller buckets.  -1 keeps the default. -->
<integer name="config_lowMemoryKillerMinFreeKbytesAbsolute">-1</integer>
<!-- Device configuration adjusting the minfree tunable in the
lowmemorykiller in the kernel.  A high value will cause the lowmemorykiller to
fire earlier, keeping more memory in the file cache and preventing I/O
thrashing, but allowing fewer processes to stay in memory.  A low value will
keep more processes in memory but may cause thrashing if set too low.  Directly
added to the default value chosen by          ActivityManager based on screen
size and total memory for the largest lowmemorykiller bucket, and scaled
proportionally to the smaller buckets. 0 keeps the default. -->
<integer name="config_lowMemoryKillerMinFreeKbytesAdjust">0</integer>

交换到zRAM

zRAM交换可以通过压缩内存页面并将它们放入动态分配的内存交换区域来增加系统中可用的内存量。

同样,由于内存的小幅增加会占用CPU时间,因此您应该仔细测量zRAM交换对系统的性能影响。

Android在几个级别处理交换到zRAM:

  • 首先,必须启用以下内核选项才能有效地使用zRAM交换:
    • CONFIG_SWAP
    • CONFIG_CGROUP_MEM_RES_CTLR
    • CONFIG_CGROUP_MEM_RES_CTLR_SWAP
    • CONFIG_ZRAM
  • 然后,您应该在fstab中添加一行如下所示:
/dev/block/zram0 none swap defaults zramsize=<size in bytes>,swapprio=<swap partition priority>
*   `zramsize`是必需的,表示您希望zram区域保留多少未压缩的内存。通常观察到30-50%范围内的压缩比。
*   `swapprio` 是可选的,如果没有多个交换区域则不需要。

您还应确保在设备特定的[ sepolicy/file_contexts](https://source.android.com/security/selinux/implement.html)中将关联的块设备标记为swap_block_device,以便SELinux正确处理它。
/dev/block/zram0 u:object_r:swap_block_device:s0
  • 默认情况下,Linux内核一次交换8页内存。使用ZRAM时,一次读取1页的增量成本可以忽略不计,并且可能有助于设备处于极端内存压力下。要一次只读1页,请将以下内容添加到init.rc
write /proc/sys/vm/page-cluster 0
  • 在你init.rcmount_all /fstab.X行后,添加:
swapon_all /fstab.X
  • 如果在内核中启用了该功能,则会在引导时自动配置内存cgroup。
  • 如果内存cgroup可用,则ActivityManager会将优先级较低的线程标记为比其他线程更可交换。如果需要内存,Android内核将开始将内存页面迁移到zRAM交换区,为已经由ActivityManager标记的内存页面提供更高的优先级。

Carveouts,Ion和连续内存分配(CMA)

特别重要的是在低内存设备上要注意清理,特别是那些并不总是被充分利用的设备 - 例如用于安全视频播放的分区。有几种解决方案可以根据硬件的具体要求,最大限度地减少削减区域的影响。

如果硬件允许不连续的内存分配,离子系统堆允许从系统内存分配内存,从而无需进行分割。它还试图进行大量分配以消除外围设备上的TLB压力。如果存储区必须是连续的或局限于特定的地址范围,则可以使用连续的存储器分配器(CMA)。

这创建了一个系统也可以用于可移动页面的分割。当需要该区域时,可移动页面将从中移出,允许系统在空闲时将大型分区用于其他目的。使用离子cma堆,CMA可以直接使用或更简单地通过离子使用。

应用优化提示

<data android:scheme="package" android:ssp="com.android.pkg1" />
<data android:scheme="package" android:ssp="com.myapp.act1" />

了解Android中的各种流程状态

  • SERVICE - SERVICE_RESTARTING
    应用程序由于自己的原因使自己在后台运行。最常见的问题应用程序在后台运行时太多了。%duration * pss可能是一个很好的“坏”度量标准,虽然这个集合非常集中,只是做持续时间百分比可能更好地关注我们根本不想让它们运行的​​事实。

  • IMPORTANT_FOREGROUND - RECEIVER
    应用程序由于任何原因在后台运行(不直接与用户交互)。这些都为系统增加了内存负载。在这种情况下,(%duration * pss)badness值可能是这些进程的最佳排序,因为其中许多将始终运行的原因很充分,因此它们的pss大小作为其内存负载的一部分非常重要。

  • PERSISTENT
    持久性系统流程。跟踪pss以观察这些过程变得过大。

  • TOP
    用户当前正在与之交互的流程。同样,pss是这里的重要指标,显示应用程序在使用时创建的内存负载量。

  • HOME - CACHED_EMPTY
    所有这些在底部的过程都是系统保留的过程,以防再次需要它们; 但是他们可以随时自由终止并在需要时重新创建。这些是我们计算内存状态的基础 - 正常,中等,低,关键是基于系统可以保留多少这些进程。对于这些过程来说,关键是pss; 这些进程应该在它们处于这种状态时尽可能地减少它们的内存占用,以允许保持最大的进程总数。一般来说,表现良好的应用程序的pss占用空间在此状态下比在TOP时要小得多。

  • TOP与CACHED_ACTIVITY-CACHED_ACTIVITY_CLIENT比较
    进程为TOP时的pss与处于这些特定缓存状态之间的pss之间的差异是查看进入后台时释放内存的最佳数据。排除CACHED_EMPTY状态会使这些数据更好,因为除了执行UI之外,由于某些原因它会删除进程启动时的情况,因此不必处理与用户交互时获得的所有UI开销。

分析

分析应用启动时间

在应用启动时,使用$ adb shell am start 命令加上 -P--start-profiler选项运行探查器。在您的任何代码加载到zygote之前,这将在您的进程从zygote创建后立即启动探查器。

使用bugreports进行分析

包含当前可用于调试的各种信息。这些服务包括batterystatsnetstatsprocstats,和usagestats。您可以使用以下行找到它们:

------ CHECKIN BATTERYSTATS (dumpsys batterystats --checkin) ------
7,0,h,-2558644,97,1946288161,3,2,0,340,4183
7,0,h,-2553041,97,1946288161,3,2,0,340,4183

检查任何持久进程

重新启动设备并检查进程。
运行几个小时,然后再次检查进程。不应该有任何长时间运行的进程。

进行长寿测试

运行更长的持续时间并跟踪进程的内存。它增加了吗?它保持不变吗?创建Canonical用例并在这些场景下运行长寿测试。

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,566评论 25 707
  • 操作系统对内存的管理 没有内存抽象的年代 在早些的操作系统中,并没有引入内存抽象的概念。程序直接访问和操作的都是物...
    Mr槑阅读 16,562评论 3 24
  • 1.1Android的官方文档主要提供了四种优化策略 1.Disable JIT,运行时动态编译,JIT编译出来的...
    android之子阅读 6,640评论 3 10
  • 2018年7月28号 星期六 晴 这周的工作基本告一段落,我自己也是,成绩比较突出,落实了好几件大事儿。 哈...
    张晨曦520阅读 544评论 0 6
  • 有一句老话是这样说的:金子遍地都是,就看你是否能捡得起来。 很多人都会这样感叹:我怎么没有发财的机会?那些发财的人...
    阿蓬阿霞阅读 946评论 26 23