资讯动态

RK3568 Android 14内存优化实战:从2GB设备中抠出211MB常驻内存

发布时间:2026/10/18 17:14:16 来源:尧图企业网站定制
1. 项目缘起为什么要在 RK3568 上死磕内存1.1 一块开发板引发的“内存焦虑”手上这块 RK3568 开发板跑的是 Android 14。板子本身不算弱四核 A55 加 Mali-G52日常跑个界面、放个视频都没问题。但问题出在内存上——整机只有 2GB 物理内存系统一启动还没等应用铺开可用内存就只剩几百兆。稍微多开两个后台或者跑一个稍重的应用系统就开始杀进程界面卡顿、应用重载体验直接崩盘。这不是个例。RK3568 这类芯片定位就是中端嵌入式市场很多方案商为了控制成本内存配置普遍在 1GB 到 2GB 之间。Android 14 作为较新的系统版本原生框架本身的内存开销就不小再加上厂商预置的各种服务、驱动、HAL 层留给应用的空间被压缩得很厉害。用户不会关心你系统占了多少他们只关心“为什么这么卡”。所以这个项目的目标很明确在不牺牲核心功能的前提下把系统运行时的内存占用尽可能压下来。最终我们做到了从基线状态抠出 211MB 的常驻内存这个数字不是靠某一个“银弹”实现的而是十几个优化点叠加的结果。1.2 211MB 到底意味着什么先把这个数字拆开看。211MB 是系统启动完成后在稳定状态下通过dumpsys meminfo和procrank交叉比对得出的常驻内存减少量。它不是某个瞬间的峰值差异而是持续稳定的释放。对于 2GB 内存的设备来说211MB 意味着什么Android 系统本身加上预置应用启动后可能占掉 1.2GB 到 1.4GB剩下 600MB 到 800MB 给用户应用。多出 211MB相当于可用内存直接提升了 25% 到 35%。这个提升带来的直接效果就是后台保活能力增强应用冷启动速度变快系统杀进程的频率明显下降。更重要的是这些优化大部分不依赖硬件改动纯软件层面就能落地。对于已经量产的方案或者正在做成本压缩的项目这套思路可以直接参考。1.3 优化前的基线状态与测量方法动手之前先得把基线摸清楚。我们用的是 Android 14 的 userdebug 版本关闭了大部分调试开关尽量模拟用户实际使用场景。测量工具主要用三个dumpsys meminfo看整体内存分布包括 Java Heap、Native Heap、Code、Stack、Graphics 等分类。procrank按进程排序看每个进程的 PSSProportional Set Size这是判断进程实际占用最准的指标。smaps汇总脚本针对单个进程看它的内存具体花在哪些映射上比如 .so 库、堆、栈、文件映射。测量时机很关键。我们统一在系统启动完成后静置 5 分钟再采集避免启动瞬间的波动干扰。采集三次取平均值减少偶然误差。基线数据如下单位MB分类基线占用系统服务system_server186SurfaceFlinger42预置应用合计215Native 守护进程合计98内核与驱动常驻320其他约 140这个表只是粗略分布实际优化时每个进程都要单独拆解。比如 system_server 这 186MB 里到底哪些是必要的哪些是可以砍掉的需要逐个服务去分析。注意测量前务必关闭所有调试工具和日志输出logd本身也会吃内存而且日志缓冲区大小直接影响占用。我们一开始没注意后来发现光调整日志缓冲区就省了十几兆。2. 整体优化思路从“能省则省”到“该省才省”2.1 内存优化的三个层次内存优化不是一刀切地砍功能而是分层处理。我们把优化对象分成三层第一层是系统框架层包括 system_server 里的各种系统服务、ContentProvider、广播接收器等。这一层的特点是“牵一发动全身”改一个地方可能影响十几个应用所以必须谨慎只动那些确实冗余或者可以延迟加载的部分。第二层是Native 层与 HAL包括各种守护进程、硬件抽象层、图形驱动等。这一层相对独立很多进程是厂商预置的功能重叠或者使用频率极低砍掉或者合并的收益很直接。第三层是应用层包括预置应用和系统自带应用。这一层最直观卸载、禁用、或者替换成轻量级实现效果立竿见影但要注意别把用户常用的功能砍没了。三层优化的优先级不同。应用层最容易动手收益也快但天花板低框架层难度大但一旦找到优化点释放的内存很可观Native 层介于两者之间需要一定的系统理解。2.2 哪些能砍哪些绝对不能动这是整个项目里最核心的判断。我们的原则是影响系统稳定性、核心交互、以及用户高频使用的功能一律不动冗余的、低频的、可替代的坚决优化。具体来说绝对不能动的包括ActivityManagerService、WindowManagerService、PackageManagerService 这些核心服务动了系统就起不来。SurfaceFlinger 和图形合成相关动了界面直接黑屏。音频、显示、输入这些基础 HAL动了设备就没法正常用。系统启动必须的 init 进程和关键守护进程。可以动的主要有厂商预置的“增值服务”比如某些统计、推送、云同步模块如果项目不需要直接去掉。重复功能的守护进程比如两个进程都在做温度监控合并成一个。低频使用的系统应用比如某些演示程序、测试工具。可以延迟加载的服务比如某些在启动时就初始化的模块改成按需加载。这个判断过程需要跟产品、驱动、应用各方对齐不能自己拍脑袋决定。我们当时列了一个清单每一项都标注了“功能描述、使用频率、依赖关系、去掉后的影响”然后逐项评审。2.3 优化顺序与依赖关系优化不能乱来得有顺序。我们的实际顺序是先做应用层清理卸载、禁用、替换预置应用。这一步风险最低收益快而且能快速验证测量方法是否准确。再做 Native 层精简分析守护进程和 HAL合并或去掉冗余部分。这一步需要驱动同事配合确认硬件功能不受影响。最后动框架层调整系统服务的加载策略、缓存大小、超时参数等。这一步最复杂需要反复测试。全局参数调优包括 LMK低内存杀手参数、ZRAM 配置、日志缓冲区等。这些是“润物细无声”的优化单独看效果不大叠加起来很可观。每一步做完都要重新测量记录数据变化。我们建了一个表格每次改动后更新这样能清楚看到每个优化点的实际贡献也方便回滚。实操心得不要一次改多个地方。我们一开始图快同时改了五六个点结果内存是降了但不知道哪个点贡献最大出了问题也不好定位。后来改成每次只动一个变量虽然慢但数据清晰复盘也容易。3. 应用层清理最直接的内存释放3.1 预置应用盘点与分类Android 14 的预置应用分几类系统核心应用如 Settings、SystemUI、厂商预置应用如各种“助手”“商城”、以及 AOSP 自带但项目可能不需要的应用如某些演示程序。我们先把所有预置应用列出来然后按“是否必须”“使用频率”“可否替代”三个维度打分。必须的保留高频的保留但可以优化低频且可替代的直接去掉。盘点时用pm list packages列出所有包名然后逐个确认。有些包名看不出功能需要反编译或者查文档。这一步花了两天时间但值得因为后面所有决策都基于这个清单。应用类型数量处理方式系统核心12保留个别优化厂商预置18去掉 11 个保留 7 个AOSP 自带9去掉 5 个保留 4 个第三方预装6全部去掉3.2 卸载、禁用与替换的取舍处理方式有三种卸载、禁用、替换。卸载最彻底直接去掉 APK 和相关的数据目录。但有些应用是系统签名或者放在 system 分区不能直接卸载需要重新打包系统镜像。我们对于确定不需要的厂商预置应用直接在编译配置里去掉这样最干净。禁用适用于那些不能卸载但又不常用的应用。用pm disable-user或者直接在编译时设置enabledfalse。禁用后应用不会启动但 APK 还在占用存储但不占内存。对于内存优化来说禁用和卸载的效果差不多因为都不运行。替换是用轻量级实现替代原有应用。比如某些系统应用功能臃肿但用户又需要基本功能我们就用一个简单的实现替换。这个工作量较大只对少数关键应用做。注意禁用系统应用时要小心有些应用被禁用后会导致其他功能异常。比如某些同步服务被禁用后账户登录可能出问题。我们当时禁了一个“云服务”应用结果设置里的账户选项直接闪退后来查了半天才发现依赖关系。3.3 应用层优化的实际收益应用层清理做完后内存下降很明显。去掉 22 个预置应用常驻内存减少了约 68MB。这个数字比预想的大因为很多应用虽然不前台运行但会注册各种广播、服务、ContentProvider后台悄悄占内存。具体来说每个被去掉的应用平均释放 3MB 左右但有些“大户”单个就占 8MB 到 10MB。比如某个厂商的“智能推荐”服务常驻内存 9MB还有一个“用户行为统计”模块占 7MB。这些在项目里根本用不到去掉后系统清爽很多。除了直接的内存释放应用层清理还带来一个隐性收益减少了系统启动时的服务启动数量启动时间缩短了约 1.5 秒。这个对用户体验也是正向的。4. Native 层与 HAL 精简动刀要准4.1 守护进程梳理与合并Native 层的守护进程是内存占用的“隐形大户”。很多进程平时看不到但一直在后台跑。我们用ps -A列出所有进程然后逐个确认功能。发现的问题主要有两类一是功能重复比如有两个进程都在做传感器数据采集一个是厂商的一个是 AOSP 自带的二是使用频率极低比如某个调试用的日志守护进程量产版本根本不需要。合并和去掉这些进程后Native 层常驻内存减少了约 45MB。其中单个最大的收益来自去掉一个厂商的“性能监控”守护进程它常驻 12MB但功能跟系统自带的性能服务重叠。进程名称功能处理释放内存厂商性能监控性能数据采集去掉12MB重复传感器服务传感器数据合并8MB调试日志守护调试日志去掉6MB厂商统计服务数据上报去掉9MB其他零散-合并/去掉10MB4.2 HAL 层的内存开销分析HAL 层是硬件抽象层每个硬件模块对应一个 HAL 服务。RK3568 平台上常见的 HAL 包括显示、音频、摄像头、传感器、蓝牙、WiFi 等。这些 HAL 服务本身占内存不多但它们的依赖库和初始化过程会消耗不少。我们重点看了几个方面一是 HAL 服务的启动时机有些 HAL 在系统启动时就加载但其实可以延迟到第一次使用时二是 HAL 的依赖库有些库被多个 HAL 共享但加载方式不合理导致重复占用三是 HAL 的配置参数比如缓冲区大小直接影响内存。优化后HAL 层释放了约 28MB。其中显示 HAL 的缓冲区调整贡献最大把默认的 4 个缓冲区减到 3 个单个缓冲区 8MB直接省了 8MB。音频 HAL 的混音缓冲区从 16MB 降到 8MB又省了 8MB。实操心得HAL 层的调整一定要跟驱动同事确认。我们当时想减显示缓冲区驱动同事说减到 3 个可以但再少就会撕裂。这种边界只有实际做驱动的人清楚文档上不会写。4.3 图形与显示相关的内存压缩图形和显示是内存消耗的大头。SurfaceFlinger 本身占 42MB加上各个图层的缓冲区总共可能上百兆。我们做了几件事第一调整 SurfaceFlinger 的缓冲区数量。默认是 3 个我们确认可以减到 2 个前提是不影响流畅度。实测在 RK3568 上2 个缓冲区在大部分场景下没问题只有极端滑动场景会有轻微掉帧但内存省了 8MB。第二压缩图层格式。有些图层默认用 RGBA8888每个像素 4 字节改成 RGB565 后每个像素 2 字节内存直接减半。当然这会影响色彩精度需要跟 UI 确认是否可接受。我们只在部分非关键图层上做了这个调整。第三减少不必要的图层。有些应用会创建透明图层或者叠加图层实际上可以合并。这个需要应用层配合我们在系统层面做了一些默认策略调整。图形这块总共释放了约 22MB效果不错但调整时一定要用实际场景测试不能只看数字。5. 框架层优化最难啃的骨头5.1 系统服务加载策略调整system_server 是 Android 的核心进程里面跑着上百个系统服务。这些服务不是每个都必须在启动时加载。我们分析了每个服务的启动时机和依赖关系把一些可以延迟加载的服务改成按需启动。比如某些打印服务、投屏服务、以及厂商定制的“智能场景”服务都可以延迟到第一次调用时再初始化。这样系统启动时少加载十几个服务内存直接省了约 18MB。延迟加载的实现方式有两种一是修改SystemServer.java里的启动顺序把服务放到PHASE_BOOT_COMPLETED之后二是用ServiceManager的懒加载机制第一次getService时才创建。第一种改动大但彻底第二种改动小但需要服务本身支持。我们两种都用了一些。对于依赖关系简单的服务直接改启动顺序对于依赖复杂的用懒加载包装。5.2 缓存与缓冲区大小调优Android 框架里有很多缓存和缓冲区默认值是为了兼容各种设备但在内存紧张的设备上这些默认值偏大。我们调整了以下几处Bitmap 缓存默认是屏幕分辨率的 2 倍我们改成 1 倍省了约 6MB。Skia 字体缓存默认缓存 512 个字形改成 256 个省了约 4MB。SQLite 缓存默认每个数据库 2MB改成 1MB系统里有十几个数据库省了约 10MB。网络缓冲区TCP 和 UDP 的默认缓冲区调小省了约 5MB。这些调整单个看都不大但加起来有 25MB 左右。而且这些缓存调小后对性能的影响很小因为大部分场景下缓存根本用不满。注意SQLite 缓存调小后数据库查询频率高的应用可能会变慢。我们实测发现对于系统自带的联系人、短信等应用影响可以忽略但对于某些频繁读写数据库的第三方应用可能会有感知。所以这个调整要看项目实际应用场景。5.3 广播与 ContentProvider 的精简广播和 ContentProvider 是 Android 里最容易“漏内存”的地方。很多应用注册了广播接收器即使不运行系统也要维护这些注册信息。ContentProvider 更重每个 Provider 启动时都会占用内存。我们做了两件事一是清理系统里的静态广播注册把一些不必要的广播接收器去掉二是合并 ContentProvider把功能相近的 Provider 合并成一个减少进程数量。广播清理省了约 8MBContentProvider 合并省了约 12MB。其中最大的收益来自把三个厂商定制的 Provider 合并成一个原来每个都独立启动合并后只启动一个进程。这个过程中要注意广播和 Provider 的清理必须确认没有应用依赖。我们用dumpsys activity broadcasts和dumpsys activity providers查看注册情况然后逐个确认。6. 全局参数与内核调优细节里的“油水”6.1 LMK 与 ZRAM 配置LMKLow Memory Killer是 Android 的内存管理机制根据内存压力杀进程。默认参数偏保守容易杀得太早或者太晚。我们根据 2GB 内存的实际情况重新调整了 LMK 的阈值。调整思路是让系统在内存还有一定余量时就开始回收而不是等到快满了才动手。这样虽然会稍微积极一点杀后台但避免了系统卡死。具体参数这里不展开因为每个项目场景不同需要根据实际应用负载调。ZRAM 是压缩内存把不常用的内存页压缩后放在 RAM 里相当于用 CPU 换内存。RK3568 的 CPU 性能够用我们开启了 ZRAM大小设为物理内存的 50%也就是 1GB。压缩算法用 lz4速度快压缩率也不错。实测 ZRAM 启用后可用内存等效增加了约 200MB当然这是“虚”的实际效果取决于压缩率。LMK 和 ZRAM 配合使用效果比单独用好很多。LMK 负责回收ZRAM 负责压缩两者结合让内存利用更充分。6.2 日志与调试开关的关闭Android 默认开启了很多日志和调试功能这些在量产版本里都是不必要的。我们关闭了以下内容logd 缓冲区默认 256KB 到 1MB改成 64KB省了约 3MB。内核日志关闭printk的调试输出省了约 2MB。ftrace 和 perf关闭内核跟踪功能省了约 4MB。调试守护进程去掉tombstoned、debuggerd等调试进程省了约 6MB。这些加起来约 15MB而且对功能没有任何影响。唯一需要注意的是关闭日志后如果出问题排查会麻烦一些所以建议在开发阶段保留量产版本再关。6.3 文件系统与 IO 调度优化文件系统和 IO 调度也会影响内存。我们做了两件事一是把tmpfs的大小调小默认可能占几十兆改成实际需要的大小二是调整 IO 调度器从cfq改成deadline减少 IO 队列占用的内存。这部分释放了约 8MB虽然不多但属于“顺手就做了”的优化。文件系统方面我们还把一些不常用的分区挂载参数改成noatime减少元数据更新间接省了一点内存。7. 常见问题与排查技巧实录7.1 内存测量不准怎么办测量是优化的基础测不准后面全白搭。常见问题有测量时机不对系统刚启动时内存波动大要等稳定后再测。我们统一等 5 分钟。工具差异dumpsys meminfo和procrank的统计口径不同要交叉验证。PSS 更准但dumpsys分类更细。缓存干扰测量前要清缓存echo 3 /proc/sys/vm/drop_caches否则 page cache 会干扰判断。后台活动测量时确保没有应用在后台跑可以开飞行模式减少网络活动。我们踩过的坑是一开始用free命令看内存发现数字忽大忽小后来才知道free把 cache 也算进去了实际可用内存要看available字段。7.2 优化后系统不稳定怎么定位优化后出问题是最头疼的。我们的排查流程是看日志logcat和dmesg一起看先找明显的错误。二分回滚把优化点分成几组逐组回滚看哪组导致问题。对比基线跟优化前的状态对比看是哪个指标异常。单点验证对怀疑的优化点单独开/关反复测试。我们遇到过一次优化后 WiFi 偶尔断连查了半天发现是某个 Native 进程被去掉后WiFi HAL 的依赖没满足。这种问题只能靠仔细梳理依赖关系来避免。7.3 常见问题速查表问题现象可能原因排查方法解决方案系统启动卡死关键服务被延迟加载看 logcat 卡在哪恢复该服务的启动顺序应用闪退ContentProvider 被合并看闪退日志的 Provider 名恢复或调整合并策略界面掉帧图形缓冲区减太多用 GPU 渲染分析工具增加缓冲区数量内存没降测量方法不对交叉验证工具统一测量标准后台被杀太狠LMK 参数太激进看 LMK 日志调整阈值音频异常音频缓冲区太小播放测试恢复缓冲区大小实操心得每次优化后至少跑一轮完整的稳定性测试包括开关机、应用切换、视频播放、网络切换等场景。我们当时为了赶进度跳过了一轮测试结果量产前发现相机打不开回头查是 HAL 调整导致的又花了两天修复。8. 优化效果与后续扩展8.1 最终收益拆解把所有优化点加起来总共释放了 211MB 常驻内存。拆解如下优化类别释放内存应用层清理68MBNative 与 HAL45MB图形与显示22MB框架层服务18MB缓存与缓冲区25MB广播与 Provider20MB全局参数与内核13MB合计211MB这个数字是多次测量取平均的结果实际使用中会有波动但整体稳定在 200MB 以上。8.2 还能继续挖的空间211MB 不是终点。后续还可以从几个方向继续优化一是应用启动优化通过预加载和缓存策略减少应用启动时的内存峰值二是内存回收策略更智能地判断哪些内存可以回收三是硬件加速利用 RK3568 的 GPU 和 NPU 分担一些计算减少 CPU 内存占用。另外Android 14 本身还有一些新特性可以利用比如更好的内存压缩、更细粒度的内存统计等。这些需要持续跟进。8.3 给同类项目的建议如果你也在做类似的内存优化我的建议是先测量再动手先应用层再框架层每次只改一个变量做好记录和回滚准备。最重要的是跟团队对齐别自己闷头改否则出了问题没人帮你定位。内存优化是个细活没有捷径但每一步的收益都是实打实的。211MB 听起来不多但在 2GB 的设备上这就是体验的分水岭。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑