EN

关于 Android 系统流畅性的一些思考

字数统计: 5.5k阅读时长: 19 min
2018/08/13
loading

版本说明(2026-10-13 核查):本文写于 2018 年。文中的机型、应用体验和厂商评价保留为当时的个人观察,旧硬件排名与购机建议已过期。下文修正技术错误,并补充 Android 10/12/13 等版本的变化;没有把历史体验当成当前版本的实测。

最近一直想写一些关于 Android 系统流畅度的东西,因为流畅度这个东西,是消费者最直接能体验到的,再加上 Android 一直为人诟病的越用越卡顿,使得大家在提到安卓机的时候,都会有一丝阴影。这也是大部分人买手机首先会考虑 iPhone 的一个原因。

由于 Google 对 Android 持开放态度,各个手机厂商生产不同产品定位的机器,以及各个 Android 应用的质量良莠不齐,导致影响 Android 流畅度的因素非常非常多,并非大家简单的以为是系统没有优化好,很多时候你会发现,不同 SOC 但是相同的系统,体验完全就是两种。

所以我想和大家聊聊影响 Android 系统流畅性的一些原因,后续大家遇到卡顿的问题,也不会单纯把锅甩给系统,或许你卸载一个 App 就解决了呢.

我想从下面几个方面展开聊这个话题:

  1. 硬件层面
  2. 系统层面
  3. 应用层面
  4. 流畅度优化闭环

准备好了,那就开始吧,欢迎你加入讨论

1. 硬件层面

CPU

CPU 是影响手机响应速度的重要器件。主线程处理业务、布局计算等工作都需要 CPU,但整机体验还取决于 GPU、存储、内存、散热和软件负载,不能只靠 CPU 判断手机档次。

原文按“高通 > 华为 > 三星 > 联发科”排列厂商,没有限定芯片型号、任务和测试条件,这个排名不能成立,也不适合作为今天的购机参考。比较时应落到具体 SoC 和整机,区分短时性能与持续负载下的表现。

GPU

各个厂商提供的 SoC 里面,通常包含了 CPU 和 GPU,例如 Snapdragon 845 搭配 Adreno 630。同一 SoC 的整机表现仍会受散热和功耗策略影响。

GPU 的能力会影响图形负载较重的应用和游戏,例如原文提到的《绝地求生:刺激战场》《崩坏 3》和赛车游戏。不过,不能只凭游戏名称判断它“吃 CPU”还是“吃 GPU”;《王者荣耀》也会随版本、场景、画质和目标帧率变化,需要看具体帧的 CPU/GPU 耗时。

Ram

2018 年写这篇时,4 GB 已经很常见了,旗舰没个 6 GB 或 8 GB,都不好意思说自己是旗舰。这是当时的市场观察和一句调侃,不能当成今天 Android 的最低要求或购机标准。

更大的 RAM 容量可以让系统以空间换时间:保留更多缓存进程和文件,减少重新加载。但容量不等于带宽,也不意味着可以无限放宽虚拟机堆、渲染缓存或预加载上限。缓存要有边界,是否变快仍取决于命中率、内存压力和实际负载。

当然如果后台进程多了又没有管住在后台跑,那么又会很耗电,有点得不偿失,这也是为什么国内的系统都会对进程管理这一块进行魔改。

UFS && EMMC

UFS 和 eMMC 都是移动设备常见的存储标准。原文讨论的是 2018 年常见的 eMMC 5.1 和 UFS 2.1,旧科普可参考这篇文章。

存储性能会影响文件读取、安装和资源加载,但接口名称不能独自决定应用流畅度,还要看随机读写、延迟、芯片实现和当前 I/O 负载。顺序拷贝快,也不代表所有启动场景都同样快。

原文“骁龙 660 不支持 UFS”的说法有误:高通 Snapdragon 660 官方产品资料明确列出 eMMC 和 UFS。平台支持与某款手机实际采用哪种存储是两件事,应查具体机型配置。

屏幕分辨率

1920 × 1080 是一种常见的 16:9 分辨率;不同长宽比的手机,不能都用这个数值概括“1080P”。更高的实际渲染分辨率通常意味着更多像素工作,可能增加渲染、合成、截图或录屏的带宽和计算成本;增加多少,要看实际渲染尺寸、硬件加速路径和瓶颈。

降低渲染分辨率可以减轻某些负载,但物理屏幕分辨率、应用渲染分辨率和录屏输出分辨率也可能不同。当年我拿魅族 MX4 Pro 举例,是因为有用户反馈它又卡又耗电;但单凭这些反馈,无法把原因全部归到 2K 屏幕上。

电池大小

电池容量会影响续航和整机设计,但续航还取决于屏幕、芯片效率、负载和温度;不同电压的电池也不能只比较 mAh。大电池本身不保证持续性能更好。

原文推荐 Oppo Find X、Vivo NEX、华为 Mate 10,是 2018 年的选购建议,现在已过期。保留这个例子,是想说明选手机时还要考虑实际使用时长和整机散热。

SoC 平台

SoC 的全称是 System-on-a-Chip。除了我们之前说的 CPU、GPU,还有其他功能模块,原文引用的科普见这篇文章,这里就不展开讲了。

SoC 是整个手机最重要的部分,是一切体验的基础。现在高通、三星、MTK 给手机厂家提供的硬件就是 Soc ,以及其配套的 Android 适配系统。手机厂商拿到这个之后,在其基础上做整机的设计,系统这边会在配套的 Android 适配系统上做移植,也就是把各家系统差异化的东西移植到新系统上。

按我在 2018 年接触高通、三星、MTK 适配系统的经验来看,高通提供的适配系统是功能最完善的,高通在 AOSP 的基础上,加上了高通自己的非常多的优化代码,并提供了完善的参数供手机厂商去配置,整体看开发起来是很舒服的,本身系统的问题不会太多,加上高通的文档完善,支持速度快,国内那么多手机厂商都在用高通也就不足为奇了。

这段评价来自当年的开发经历,没有提供统一对比测试,不代表这些厂商今天各平台的质量排序。

至于专利费,该给的要给啊。

我们经常会说,如果魅族早点用高通的 Soc,早 TM 上市了。

2. 系统层面

应用的管控策略

大部分 Android 应用开发者对国内的手机厂商恨的咬牙切齿,最大的原因就是国内系统对应用管控这一块进行了大量的魔改,除非你是 QQ 或者微信,否则灭了屏结果都一样。

国内厂商这么做,不是没有原因的,国内应用厂商的全家桶相互唤醒,已经到了一种丧心病狂的地步,牵一发而动全身,一点都不夸张。

在当时我们处理的一些整机卡顿反馈中,抓 Trace 和 Log 来看,都是后台有应用在乱跑,或者后台大量的进程常驻,内存根本不够,而这些普通用户根本就不知道怎么去处理。

下面是当时一些厂商的限制思路,具体策略因 ROM、应用权限和用户设置而异,并不是 Android 对所有后台行为的统一禁令:

  1. 除非必须,一个应用偷偷拉起来另外一个应用的行为是不被允许的
  2. 除非必须,一个应用常驻后台是不被允许的
  3. 除非必须,一个应用在灭屏后在后台乱跑是不被允许的
  4. 除非必须,一个应用在后台长时间占用 cpu 是不被允许的
  5. 除非必须,一个应用弹窗是不被允许的

另外手机厂商会有其他的逻辑清理后台的应用,尽管你是合理存在的。

严格的后台管控会影响远程消息的送达,但“未接入厂商 Push SDK 就不能发通知”说得过头了。应用发布本地通知、远程消息到达设备、点击通知后打开界面,是三个不同环节。在具备相应服务和网络条件的设备上,FCM 的后台 notification 消息可以由系统通知栏呈现;厂商推送则有各自的接入与运行条件。

Android 13(API 33)起,普通非豁免通知还受 POST_NOTIFICATIONS 运行时权限约束;通知渠道和用户设置也会影响显示。进程已被回收时,点击通知可能需要冷启动,但等待多长还取决于应用初始化和目标页面,不能一概归因于厂商 SDK。

内存策略

手机厂商会根据内存容量和产品目标,调整缓存进程、内存压力处理及渲染缓存等策略。原文的 LowMemoryKiller 阈值描述带有旧版本背景:Android 9 起,在没有内核 LMK 驱动时使用用户态 lmkd;Android 10 增加基于 PSI 的压力检测,Android 11 又调整了回收压力与 thrashing 的杀进程策略。启用方式仍依赖内核支持和设备配置,见 AOSP lmkd 文档。

在当时排查的一些低内存设备上,我们见过后台反复被杀、重新加载和 CPU 占用升高的问题。不过,内存回收不都等于“把内存写到磁盘”:干净的文件页可以丢弃,需要时再读入;部分匿名页可以压缩到 RAM 中的 zRAM,设备也可能配置额外的 zRAM 写回机制。见 Android 内存分配说明。

Trace 里的 Block I/O 只能作为线索。要结合回收、缺页、实际 I/O 等待和进程重启时间,确认这些工作是否阻塞了当前帧。原文“内存需求只会上升,尽量买 8 GB”的建议已过期;容量、后台保留目标和工作负载需要一起评估。

进程调度策略

渲染依赖的线程如果迟迟拿不到 CPU,可能错过这一帧的截止时间。Trace 中的 Runnable 区间表示线程可运行、正在等待 CPU;这也可能发生在运行后被抢占的阶段,不能仅凭一个长 Runnable 就判定调度器有问题。

常见排查方向包括:

  1. 同时可运行的线程过多,CPU 已被其他任务占用。
  2. 线程优先级、CPU 亲和性或 cpuset 限制了它可以使用的资源。
  3. 调度唤醒、迁移和负载变化没有及时配合,需要结合具体调度事件分析。

CPU 频率、温控限制,以及大核与小核之间的迁移,也可能改变任务完成时间。但“跑到小核”本身不等于卡顿,要看它是否能在截止时间前完成。

WMS/AMS 锁竞争和 Binder 等待要另看依赖链:线程可能在睡眠或等待唤醒,并不一定处于 Runnable。先区分“在 CPU 上执行得慢”“等 CPU”和“等其他线程/资源”,再找原因。调度数据的采集与含义可参考 Perfetto CPU Scheduling。

系统调优往往需要针对上面的情况做对应的处理,给用户一个好的用户体验。具体的调优方式,往往跟系统和 SoC 强相关,又涉及到 Kernel 和功耗,改起来是牵一发而动全身,需要非常谨慎。

渲染线程和主线程

对使用硬件加速 View/HWUI 的应用,主线程和 RenderThread 都是排查对象。RenderThread 随渲染器使用按需建立,不能说每个应用都在进程启动时同时创建这两个线程;游戏自有渲染路径也未必遵循同一结构。Android 5.0 的具体调用路径见RenderThread 流程分析。

Profile GPU Rendering 柱图可以帮助发现某些帧阶段变长,但它不是 GPU、SurfaceFlinger 和屏幕呈现的完整计时。出现异常后,需要继续查看 Trace,常见方向包括:

  1. 较长时间的 input 事件处理。
  2. 较长时间的动画或列表更新逻辑,包括 Item 创建和绑定。
  3. 复杂界面的 Measure、Layout、Draw。
  4. 大 Bitmap 的频繁上传。
  5. 复杂渲染指令、GPU 工作或缓冲区等待。

这些方向不代表所有卡顿都发生在应用主线程或 RenderThread 上。系统合成、显示调度和资源竞争同样可能影响最终呈现。

优化的目标是让关键任务按时完成,同时兼顾输入、音频、其他必要任务与功耗。把前台整条渲染链都设成“最高优先级”,不能保证消除资源竞争,也可能损害系统其他功能。

TripleBuffer

Android 4.1 的 Project Butter引入了同步节奏和三缓冲等改进。三缓冲能让生产与消费帧更好地流水执行,但排队也可能增加输入到显示的延迟,它不能保证耗时超标的帧不发生卡顿。

60 Hz 的刷新间隔约为 16.67 ms,90 Hz 约为 11.11 ms,120 Hz 约为 8.33 ms。这些是刷新间隔,不是所有场景都适用的单线程预算。单看 GPU Profile 柱子是否越过 16 ms,既不能完整证明卡顿,也不能用“三缓冲”排除卡顿。

Android 12(API 31)起可以结合 Perfetto FrameTimeline,查看预期与实际时间线、呈现是否延迟,再关联 CPU/GPU 和 SurfaceFlinger 工作。它有版本、采集配置和渲染路径的覆盖边界;没有对应数据时,不能记成“零卡顿”。

虚拟机 - Art 和 Dalvik

ART 改进了代码执行和内存管理,但不会让主线程彻底摆脱 GC 暂停。以 Android 8.0 默认的 Concurrent Copying 收集器为例,大量工作可以并发完成,仍然存在暂停阶段;分配压力、等待线程到达暂停点等因素也会影响耗时。见 AOSP ART GC 调试说明。

所以要同时看分配速率、GC 次数、暂停时间,以及它们是否与慢帧重合。不能把 Dalvik 时期所有卡顿都归到 GC,也不能因为用了 ART 就跳过这部分分析。

温控 && 低电量

温控、低电量省电模式和设备空闲限制是不同机制。它们可能影响 CPU/GPU 频率、后台任务或网络,但具体行为由版本、设备和当前状态决定;不能说一触发温控就必然关核心、杀进程、关特效和断网。

持续游戏后变卡,可能与热限制有关,也可能是场景负载、内存或网络变化。Android 10(API 29)提供 PowerManager 热状态监听,可以与帧耗时一起观察;游戏还可以通过 ADPF 的热管理指导调整帧率和画质,在设备可持续的负载下运行。

所以说选购手机的时候,除了要看 SoC,还要看散热是否做的够好。电池大并不能代替散热设计。

3. 应用层面

复杂的布局

复杂布局可能增加 Measure、Layout、Draw 的工作,拖慢主线程;但层级深浅本身不是结论,要看实际遍历次数、耗时和是否错过帧截止时间。

ListView、RecyclerView 的新的 Item 在初始化的时候也会有类似的问题,由于此时一般是在滑动,这时候的卡顿感会更明显,用户也更容易察觉,这个从 Trace 上也很容易看出来。

过多的业务逻辑

下面保留的是我在 2018 年对淘宝启动体验的吐槽,不代表当前版本:

过多业务逻辑导致的卡顿和响应慢的问题,拿淘宝来举例子最合适不过了,每次你冷启动淘宝的时候,进入主界面马上滑动,总感觉跟吃了屎一样,点按钮点不动,滑界面滑不动,虽然最近的版本有优化,不过你找个低端 Android 机,还是原来的配方。

启动时如果同步加载大量模块、初始化业务或争抢 CPU,首页已经显示也可能难以操作。不过,本文没有附当时的完整 Trace,不能据此确认每次淘宝冷启动都有大量 dex2oat 工作。

AOSP 的 ART 编译说明区分解释执行、JIT 与基于 profile 的 AOT 编译。具体编译行为受安装、已有编译产物、使用记录和系统策略影响;冷启动不等于重新编译整个应用。现代应用还可用 Baseline Profiles优化常用路径,但仍需分别验证首帧和业务可用时间。

内存颠簸

短时间内大量分配临时对象,可能增加 GC 频率和 CPU 开销。Android Studio 内存曲线呈锯齿状,只说明分配与回收在发生,正常应用也会这样;它不能单独证明代码错误或内存泄漏。

要结合分配热点、GC 暂停和帧时间判断是否需要优化。如果一次操作结束、完成回收后,仍保留了不该存在的对象,再继续检查引用关系。

慢网络

慢网络会让内容迟迟不出现,用户也可能把这种等待叫作“卡了”。但它与渲染掉帧不是同一指标:异步请求尚未返回时,界面可以仍然流畅;若主线程被网络、解析或后续更新阻塞,才需要沿线程和渲染路径继续排查。

不合理的设计

复杂设计需要评估性能成本,再决定实现和取舍,设计师的设计往往很炫酷,互相嵌套的动画往往是程序员的噩梦,为了实现这些复杂的效果,程序员往往需要复杂的代码来实现,这对应用的渲染链路的压力是非常大的,而且在不同性能的机器上表现差异很大,高端机用户觉得这个效果棒棒哒,低端机用户卡的要骂娘。

程序员需要有这方面的知识和数据,好与设计师动之以情晓之以理。

不过用户是很挑剔的,现在的用户对性能的要求越来越高,哪怕是低端机用户,所以合适的设计应该考虑到这部分用户、或者针对低端机用户做区分。

代码实现错误

俗称 bug ,很多程序员不喜欢解决性能问题,因为这个东西解决起来,性价比很低,拿我司的程序员来说,解一个性能问题的时间,可以解决十几个界面显示的问题,还未必能真的解决。

不过由于代码实现错误引起的性能问题,必须要最高优先级解决。

4. 流畅度优化闭环

实验室监控 && 模拟用户

开发阶段就用各项数据来做监控和对比,尽量模拟用户的使用环境,尽早暴露性能问题,早日解决。对比时记录设备、系统与应用版本、刷新率、温度和编译状态,区分启动等待、交互响应和渲染掉帧,避免把不同条件下的数据直接比较。

用户流畅度数据收集

在用户使用阶段,收集性能数据,针对这些数据做分析,找出用户最多遇到的性能问题,针对性地做优化。此时也要控制采集频率和开销,收集太多信息会产生观察者效应。

至于采集哪些数据,可以先从与慢帧同时出现的 CPU 等待、内存压力、热状态等指标入手。相关性只是排查线索,不能直接当成因果;仍需回到具体场景和时间线验证。

另外用户的场景判断也非常重要,需要知道用户是在哪个场景出现的卡顿,一旦用户的数量到了一定的级别,这个是很容易发现问题的。

针对性地优化

大数据发现问题后,后续就是针对性地进行优化,把用户最常遇到性能问题的场景进行排序,对最常见的场景进行调研和优化。很多时候需要与应用开发厂商进行沟通,

然后需要把这些场景纳入到实验室监控环境里,做到 实验室监控 —> 模拟用户 — > 大数据收集 —> 针对性优化 —> 实验室监控补充. 这样一个闭环。

关于我 && 博客

下面是个人的介绍和相关的链接,期望与同行的各位多多交流,三人行,则必有我师!

  1. 博主个人介绍 :里面有个人的微信和微信群链接。
  2. 本博客内容导航 :个人博客内容的一个导航。
  3. 个人整理和搜集的优秀博客文章 - Android 性能优化必知必会 :欢迎大家自荐和推荐 (微信私聊即可)
  4. Android性能优化知识星球:付费社群已于 2026 年停止运营,不再招收新成员;此处保留历史介绍。

一个人可以走的更快 , 一群人可以走的更远

微信扫一扫

CATALOG
  1. 1. 1. 硬件层面
    1. 1.1. CPU
    2. 1.2. GPU
    3. 1.3. Ram
    4. 1.4. UFS && EMMC
    5. 1.5. 屏幕分辨率
    6. 1.6. 电池大小
    7. 1.7. SoC 平台
  2. 2. 2. 系统层面
    1. 2.1. 应用的管控策略
    2. 2.2. 内存策略
    3. 2.3. 进程调度策略
    4. 2.4. 渲染线程和主线程
    5. 2.5. TripleBuffer
    6. 2.6. 虚拟机 - Art 和 Dalvik
    7. 2.7. 温控 && 低电量
  3. 3. 3. 应用层面
    1. 3.1. 复杂的布局
    2. 3.2. 过多的业务逻辑
    3. 3.3. 内存颠簸
    4. 3.4. 慢网络
    5. 3.5. 不合理的设计
    6. 3.6. 代码实现错误
  4. 4. 4. 流畅度优化闭环
    1. 4.1. 实验室监控 && 模拟用户
    2. 4.2. 用户流畅度数据收集
    3. 4.3. 针对性地优化
  • 关于我 && 博客