渲染内存降95%、GC卡顿率降90%:KMP 是怎么在鸿蒙上跑起来的
点击查看原文>
从 PC 时代到多端鼎立:跨平台不是新故事
回顾移动开发的历史,跨平台的需求几乎和移动应用本身一样古老。
PC 时代,用户在浏览器里输入一个 URL 就能跳转到目标页面,开发范式简单直接。后来乔布斯推出 iPhone,因为早期手机性能有限,原生 App 成为承载移动体验的重要方式。为了吸引开发者入场,苹果发明了 App Store。更准确地说,是 App Store 首页上那个小小的图标。
这个图标对开发者的吸引力极大,原因并不复杂:拥有一个入口按钮,意味着开发者第一次掌握了自建流量的能力,于是大量开发者和企业开始进入移动应用生态。
随后,Android 兴起,行业从相对统一的 PC、Web 时代,逐渐进入 Web、Android、iOS 多端并存的阶段。
问题也随之而来:一个应用要同时覆盖 Android、iOS 和 PC,意味着几套代码、几个团队、和几倍的成本。开发者开始怀念"写一套代码到处跑"的高效时代。
Facebook 率先给出了自己的答案,把 React 的开发范式搬到移动端,这就是 React Native。但随着应用复杂度上升,React Native 的性能问题逐渐显现。
与此同时,Google 内部一群做 Chrome 的顶尖工程师也在思考同样的问题。他们发现 Chrome 在移动端的性能表现很差。PC 端硬件强劲,Chrome 可以堆功能、强调并发能力。但移动端的 CPU 资源极其有限,Chrome 那套为 PC 设计的架构在手机上水土不服。具体表现为:长列表滑动时跟手性还行,但白屏频出。这在 Web 端不算什么,在移动端就是 Bug。
于是他们决定重构整个渲染管线。核心思路是:从强调并发能力,转向一条精简的渲染流水线,强调即时渲染,内容要立刻出来,不能等。由于渲染链路更短,出现问题时也更容易定位。
这就是 Flutter 的技术起点。
Flutter 还有一层更深的战略意图,Google 的生态嗅觉一向敏锐,在为未来的 AI 和 IoT 设备做准备之外,Flutter 的推出也意在发展开发者生态。至于 Flutter 的另外一重使命,就是要统一多端的 UI。这也是其在国内风靡一时的原因。
另一条演进路线来自 Android 自身。2018 年,Jetpack 推出,改善了传统 Android 开发中 XML 与 Java 代码混杂、开发方式相对粗糙的问题,并提供了 Lifecycle 等更加完整的工程能力。2021 年,Jetpack Compose 推出,声明式 UI 从 Web 进一步进入移动原生开发,SwiftUI 也采用了类似的声明式范式。
在某头部互联网公司内部,Compose 刚推出时开发人效就有 1:1.6 的提升,一个人能干 1.6 个人的活。当然那时 Compose 还不太成熟,性能问题不少。
到了 2023 年,KMP 开始受到更多关注。如果说 Flutter 的核心是统一 UI,那么 KMP 的核心就是统一业务逻辑。这也代表了跨平台框架的又一次代际变化。
从统一 UI 到共享逻辑
Flutter:自渲染带来一致性,也形成性能边界
Flutter 的关键技术是自渲染。开发者使用 Dart 编写一套代码,便可以运行在 Android、iOS 和 Web 等平台上。此后,Flutter 又引入 Impeller,以更现代的 GPU 渲染方式逐步替代 Skia,并利用 Vulkan 等图形接口改善渲染性能。
Dart 在国内的接受度相对有限,因此不少团队尝试将 Flutter 的开发语言替换为类 TypeScript 或 JavaScript 语言,例如腾讯的 MXFlutter。行业中甚至一度有一种观点:如果 Flutter 使用 JavaScript,它可能会成为更加理想的跨平台框架。
Flutter 未来可能会面临生态变化,但它所代表的自渲染技术路线不会轻易消失。框架可能退潮,具有独特价值的底层技术却会被保留下来。
KMP:以更细粒度的方式共享逻辑
KMP 与 Flutter 的设计理念不同。Flutter 试图统一 UI,KMP 则更加关注共享逻辑,这种差异主要体现在架构模式和交互性能两个方面。
在 Flutter 中,如果需要调用原生能力,通常要编写 Platform Channel。随着业务复杂度上升,一个图片库、网络库或其他组件可能对应大量通道代码,整体粒度偏粗。跨端与原生之间还需要进行序列化和反序列化,在高频交互场景中容易产生性能损耗,甚至引发卡顿。
KMP 引入了 Expect/Actual 机制。公共层可以声明统一接口,各平台再提供具体实现,其复用粒度既可以很粗,也可以细化到函数和属性。这样既能提高开发效率,也能保留调用平台原生能力的灵活性。
在性能方面,KMP 可以直接调用平台 C 接口,直接生成各平台原生二进制代码,性能可能获得数倍甚至接近两个数量级的提升。
因此,KMP 的下一代特征主要体现在两点:一是提高共享逻辑的开发效率,二是降低跨端逻辑与原生平台交互的成本。

为什么国内大厂纷纷押注 KMP
KMP 在海外的应用规模一度并不算大,但在国内,越来越多大型企业开始押注 KMP,其中一个重要原因是鸿蒙生态的崛起。
当企业需要同时维护 Android、iOS 和鸿蒙三端时,很难再为每个平台分别扩充一支完整团队。尤其在成本压力较大的情况下,企业希望通过跨平台框架解决新增平台带来的研发投入问题。
从业务模式看,一个大型移动应用通常可以拆成三个区域:
性能域:与业务强相关、出问题损失大的场景(如购物应用从首页到购物车到下单),需要高性能和高稳定性,一般用原生或 KMP;
动态域:种草类页面,运营和产品希望今天设计方案明天就能上线,对性能要求不高但要求高动态性,一般选 Lynx、Weex 等类 RN 框架;
开放域:航母级 APP 希望用户所有时间都停留在自己生态内,通过支付宝小程序、微信小程序等方式接入第三方。
过去,性能域往往只能选择原生开发,因为业界缺少真正成熟、可落地的高性能逻辑跨平台框架。
从语言角度看,C++ 的内存管理门槛较高,Rust 的学习曲线较陡,JavaScript 和 Dart 的性能上限又相对有限。Kotlin 和仓颉在语言性能上具有一定潜力,但当时也各有短板:Kotlin 在 Android 上生态强大,在 iOS 和鸿蒙上的基础设施仍不完善;仓颉的运行时和性能表现不错,但生态尚处于早期阶段。
某个头部应用曾计划两年内把跨平台框架占比从 45% 提升到 75%,但由于缺乏逻辑跨平台能力,只能双线并行:一边提升 JS 框架性能,一边试点 KMP 和仓颉 CJMP。
这意味着,逻辑跨平台已经从一项技术探索变成了现实刚需。
过去开发者做跨平台框架时,面对 Android 和 iOS 这样的成熟生态,更多是仰望和遵循。特别是 iOS,平台方处于生态顶端,可以制定应用上架、下架以及能力使用规则,开发者必须遵守。为了实现动态化等能力,团队有时不得不在规则边界内寻找复杂的技术路径。
鸿蒙作为后来者,所处的位置不同。为了吸引开发者、兼容既有生态,它需要在操作系统层面做更多适配和开放。例如,为了支持 KMP,鸿蒙开放了不少 CAPI;React Native 适配鸿蒙时,由于桥接 ArkTS 的性能不足,系统也曾紧急开放 CAPI,供框架进行更高效的调用。
跨平台的代价:效率与体验的永恒博弈
跨平台框架带来了效率提升,Flutter 典型的提效比例是 1:1.5,到了鸿蒙阶段基本是两个人干三个人的活。但效率不是免费的,代价主要体现在三个方面:
性能与体验问题。 跨平台框架强调通用性,很难针对每一个平台进行足够深入的定制。Flutter 会面临包体积、内存占用、启动速度以及原生交互等问题。引入跨平台框架通常也意味着引入一种非原生语言,频繁的跨语言调用会增加额外开销。多语言运行时还可能带来更复杂的对象生命周期问题。例如 React Native 与 Android 原生代码之间可能形成相互引用甚至引用环,导致对象无法及时释放。业务团队需要对两侧的内存模型都足够了解,才能规避这类问题。
生态与碎片化问题。 国内不少头部厂商会基于开源框架进行深度定制,形成私有版本。此后,即使鸿蒙侧修复了 Flutter 的某些问题,也很难将改动顺利推送到所有应用厂商维护的分支中。
技术复杂性与维护问题。 引入一套新技术栈后,疑难问题可能横跨业务代码、跨平台框架与原生系统。工程师必须理解整条链路,才能找到真正的故障位置。这里还存在“抽象泄漏”问题。跨平台框架试图用统一抽象抹平平台差异,但差异很难被完全消除,业务代码中最终仍可能出现大量与平台相关的 if/else。
跨平台框架提升了复用效率,却不会自动消除平台复杂性;很多时候,它只是把复杂性从业务层转移到了框架层。
Flutter 在鸿蒙上的适配与优化
鸿蒙为了支持 Flutter,对运行时、UI、跨语言调用、第三方库和开发命令行等关键模块进行了适配。
其中,第三方库的工作量尤其大。Flutter 生态中存在数以万计的第三方库,2025 年紧急完成了 Top 30 核心库的适配,此后的覆盖范围还在持续扩大。在完成基础适配后,鸿蒙又围绕渲染性能和系统垂直整合进行了优化。
Impeller:降低首次渲染抖动
Impeller 能够逐步替代 Skia,一个重要原因是它解决了着色器编译问题。
传统 Skia 会在运行时编译着色器。首次进入页面时,这一过程可能消耗 100~200 毫秒,造成至少 6~7 帧的丢失。Impeller 在构建阶段预编译着色器,从而减少首次渲染时的卡顿。
另一方面,传统 OpenGL 渲染链路对 GPU 并行能力的利用有限。Impeller 引入 Vulkan 等现代图形接口后,可以更充分地使用 GPU。鸿蒙较早进行了 Impeller 适配。从测试结果看,页面帧率得到明显提升,GPU 利用更加充分,CPU 负载也随之下降。
通过共享内存实现外部纹理零拷贝
Flutter 使用独立的自渲染管线,而 Android、iOS 或鸿蒙自身也有原生渲染管线。摄像头、播放器等场景产生的图像需要在两套 GPU 上下文之间传递,如果直接搬运 Buffer,往往需要经过 GPU、CPU 再回到 GPU,成本很高。
鸿蒙驱动层引入了共享内存机制,传递外部纹理时不再复制完整 Buffer,由两套渲染管线共享底层内存。这样可以把数据传递的额外开销降到很低,并解决当时微信视频播放和 VoIP 场景中的明显卡顿问题。
不过,Flutter 仍存在难以绕开的性能边界。
首先是自渲染的内存消耗。以 1080P 手机为例,单个 Flutter 页面大约会增加 70MB 内存占用;如果同时存在 N 个 Flutter 页面,额外开销可能接近 N×70MB。
其次是 Dart 的并发与内存共享能力。Dart 通过强类型解决了 JavaScript 动态类型带来的部分问题,但线程间内存共享等能力仍存在限制。因此,从语言和运行时角度看,Flutter 很难在所有场景中达到甚至超过原生性能。
面对 AI 时代,Flutter 的动作相对激进。除了使用 Impeller 重构渲染链路、持续优化 Web 端性能,它还推出了 GenUI,并围绕 A2UI 协议探索使用自然语言生成 UI。在开发链路中,Flutter 也开始引入统一的 AI 工具,使开发者可以调用 Gemini、OpenAI、Claude 等模型与服务,并通过 ML Kit 等方式使用端侧智能能力。
KMP 在鸿蒙上的三项关键改造
从 2025 年开始,华为与多家生态伙伴合作推进 KMP 在鸿蒙上的建设。合作初期,伙伴反馈了大量问题,包括跨语言通信、内存占用、DFX 能力、包体积和编译性能等。KMP 在 Android 上接近原生体验,但在鸿蒙和 iOS 上的基础设施当时仍相对粗糙。
2026 年 6 月,鸿蒙发布了首个 KMP 公版。从 2025 年只能支持简单页面,到分享时已经可以承载更加完整的应用与页面开发,整个体系发生了明显变化。其余仍在建设的问题,按照规划将于 2026 年 9 月前陆续解决。
这些工作将主要围绕渲染、运行时和开发效率展开,目标不是让 KMP 在鸿蒙上勉强可用,而是使其性能接近原生,部分场景甚至有机会超过 ArkTS 原生实现。
从自渲染走向半自绘
Flutter 采用自渲染机制,由此带来了包体积、内存和原生混排问题。例如,在 Flutter 页面中“挖一个洞”,透出下方的原生页面时,可能出现透明度无法正确设置、拖拽过程中图层错位等问题。
现在更值得关注的一种方式是“半自绘”。组件和文本仍然由框架生成绘制命令,但底层复用原生渲染管线,而不是重新创建一套完整的 GPU 环境。
这样做有三个直接好处:
不必重复申请大量渲染内存;
不必重新创建 GPU 环境,启动速度更快;
可以更自然地解决跨平台内容与原生内容混排的问题。
以 Compose 实例为例,每个实例可能需要创建约五个 Buffer。如果一个页面存在 10 个实例,额外开销可能接近 500MB。复用原生渲染管线后,这部分内存可以大幅下降。
基于原生渲染管线,还可以进行更加深入的系统垂直整合。例如,一个页面中只有局部节点发生移动时,理论上不需要重新绘制整个区域。而是可以缓存对应的子树结构,在节点移动时只调用 transform 接口修改位置,从而减少重复绘制。
用 CMC 降低 GC 长卡顿
2025 年时,KMP 在鸿蒙和 iOS 上使用的 GC 算法仍接近早期 CMS 的水平。它主要存在两个问题:容易产生长时间卡顿,以及内存碎片较多。
按照原有机制,GC 在扫描对象时难以准确区分某个值究竟是指针还是普通数据。虽然 Mark 阶段可以并行执行,但对象难以安全移动。运行一段时间后,堆中会出现大量不连续的内存空洞。此时即使剩余内存总量足够,也可能无法申请一块较大的连续空间。
系统随后不得不触发 Stop-the-World,暂停主线程并重新整理内存,卡顿时间可能达到几十甚至上百毫秒。
为此,鸿蒙开发了 CMC 算法,重点解决并发度和碎片化问题。
第一项改造是按照对象大小将内存划分为多个 Region,为不同 Region 分配独立线程进行管理,提高 GC 并发度。
第二项改造是引入 Stack Map,记录对象引用信息,使运行时可以更准确地判断对象引用关系,并在 GC 过程中移动对象。对象能够从 From Space 拷贝到 To Space,碎片整理便可以分散到日常 GC 中完成,而不是等问题积累到一定程度后再进行一次耗时很长的大清理。
这就像平时持续打扫房间,而不是等到房间彻底无法使用时,再停下所有工作进行一次大扫除。
并行编译带来 2~4 倍提升
过去编译 KMP 工程时,大量 Kotlin 文件会被编译成一个巨大的 LLVM IR 文件,再进行全局优化,最终生成一个大型 .so 文件。这个过程难以充分并行。
鸿蒙的改造思路是把一个大型 LLVM IR 拆分成多个 IR 模块,并在模块内部进一步并行编译。
拆分后也产生了两个问题。
第一个是包体积变大。模块独立编译时,需要导出更多 Symbol,供其他模块调用,其中一部分最终并不会真正被使用。
第二个是运行性能下降。为了实现模块化,早期方案关闭了部分全局变量优化 Pass,使编译器无法继续完成原有的全局优化。
解决方法是在拆分前记录真正需要暴露的 Symbol,并在打包后清理不再需要的中间 Symbol。同时,我们为全局变量信息建立缓存,使每个模块在编译时仍能识别需要优化的全局变量。
解决包体积和性能退化问题后,并行化编译使 KMP 的整体构建速度提升了约 2~4 倍。
KMP:AI Coding 的全流程赋能
鸿蒙突击队正在与多家厂商合作探索覆盖完整研发流程的 AI 开发,其中重点包括 A2K(Android2KMP)和 D2C(Digital2Compose)。
AI Coding 在大型工程中主要面临三个挑战。
第一,代码量巨大。头部应用通常积累了大量 Kotlin、ArkTS 等代码,模型需要理解完整工程,而不是只处理一个孤立函数。
第二,代码质量难以控制。AI 生成代码具有一定黑盒属性。有些团队在生成代码后甚至不进行充分验证就直接提交,这会带来明显风险。
第三,企业存在大量私域知识。每家厂商的基础设施、编码规范和内部组件都不同,通用 AI 工具很难直接理解这些信息。
A2K:从理解工程到生成可用代码
A2K 的流程包括:理解原始项目、生成 Spec、完成初版代码转换、对齐测试和性能结果,最后生成可交付代码。
在这个过程中,鸿蒙重点做了两件事。
一是复用原工程已有的测试用例资产。测试用例不仅用于验证结果,也能帮助模型理解原代码的真实行为边界。
二是从源代码中识别并抽取基础模块。在生成初版代码时,将目标工程容器和基础设施能力一并嵌入,避免模型只完成表面语法转换,却无法接入真实业务环境。
经过这些改造,A2K 生成代码的采纳率达到约 60%。
D2C:为什么需要引入中间表示
D2C 最初采用一步到位的方式,直接将 Figma 设计稿转换为 Compose 代码。但实际使用时经常出现问题。
例如,模型可能无法正确理解图层关系,导致 z-order 错误;Figma 中还可能存在写死的偏移值,转换后的页面在其他尺寸屏幕上会短一截或多一截,难以完成多设备适配。
后来,我们不再直接生成 Compose,而是在中间引入 React 作为 IR。
选择 React 有两个原因。第一,React 与 Compose 对大模型而言具有较高的范式相似性,二者都采用声明式、响应式 UI,React 到 Compose 的转换相对顺畅。第二,React 生态已经非常成熟,存在大量 Figma to React 工具,可以更好地完成设计稿的初步结构化。
拆成“Figma 到 React、React 到 Compose”两个步骤后,过去难以解决的尺寸偏差和层级错误基本得到改善。在某厂商满分 100 分的评估体系中,整体得分提高了约 10 分。
React 还带来了调试优势。中间结果可以直接在 Chrome 中展示和调试,团队能够先判断 UI 结构是否正确,再进入 Compose 代码生成阶段。
AI Coding 并不意味着步骤越少越好。必要的中间表示,可以把一个不稳定的大问题拆成两个更容易验证的小问题。
AI 时代,跨平台框架该如何选?
从 React Native、Flutter 和 KMP 三条路线来看,AI 带来的影响并不相同。
React Native 受到的冲击最大。它最初的核心价值之一,是让前端工程师可以开发移动应用。但在 AI 可以辅助生成原生代码之后,这一优势正在减弱。
React Native 仍具备天然的动态化能力,但 H5 等方案也可以满足不少动态化需求。与此同时,Meta 已经在部分页面中减少 React Native 的使用,其生态热度也有所下降。因此在新的项目中,建议谨慎选择 React Native。
Flutter 最突出的价值仍是多端 UI 一致性。如果一个应用强调不同平台上的统一视觉体验,对原生 UI 能力、启动速度和包体积又没有极高要求,Flutter 仍然是合适的选择。
KMP 更适合国内三端并行的环境。一方面,它可以复用 Android、iOS 和鸿蒙之间的业务逻辑;另一方面,国内企业已经积累了大量 Kotlin 代码,迁移成本相对可控。KMP 通过 Kotlin/Native 生成原生二进制,性能表现也更加接近原生。
结合当前国内环境,一个可供参考的判断是:
如果需要面向 Android、iOS 和鸿蒙进行长期建设,战略上优先考虑 KMP;
如果高度强调多端 UI 一致性,对原生 UI 和极致性能要求不高,可以选择 Flutter;
对于 React Native,应结合动态化需求和生态趋势谨慎评估。
不过,AI 能生成原生代码,并不意味着跨平台框架会失去价值。
某公司在裁员 50% 后,希望用 AI Coding 补充研发能力缺口,同时通过 KMP 统一技术栈,降低团队维护多套开发体系的负担。另一些公司也在考虑将后续 AI Coding 的目标技术栈统一切换到 KMP。
原因很直接:如果 AI 分别生成 Android、iOS 和鸿蒙三端代码,工程师在调试时仍然需要理解三套技术栈。跨平台框架能够抹平一部分平台差异,这种效率杠杆不会消失,反而可能因为 AI 大规模生成代码而进一步放大。
框架还可以统一 UI 行为,并集中解决平台兼容性问题。特别是在 Android 设备碎片化严重的情况下,许多兼容适配不应该由每个业务团队重复处理,而应沉淀到框架层。
AI 时代,跨平台框架的核心问题正在从“如何让开发者更高效地编写多端代码”,转向“如何让 AI 生成更高质量、可验证、可复用的多端代码”。
这要求框架提供更清晰的抽象、更完整的测试资产、更稳定的工具链,以及能够被 AI 调用和理解的开发者生态。
结语:共享逻辑、原生 UI 与 AI 的混合工作流
从国内市场的发展趋势看,KMP 的共享逻辑能力与鸿蒙生态建设之间具有较高契合度。它既能兼容 Android 侧的 Kotlin 存量代码,也能帮助企业降低新增鸿蒙端的研发成本。
但对于追求极致体验的大型应用,仅仅复用 UI 并不一定是最佳选择。Flutter 或 Compose Multiplatform 很难完整复现每个平台的所有原生体验,例如 iOS 的原生转场交互、Android 的水波纹效果等。原生 UI 仍然具有不可替代的价值。
未来三年,共享逻辑加原生 UI,很可能成为跨平台开发的主流形态。
在此基础上,AI 将参与需求理解、代码迁移、UI 生成、测试验证和性能对齐,形成一种新的混合工作流:
原生 UI 负责平台体验,KMP 等框架负责共享逻辑,AI 负责放大开发与迁移效率。
跨平台框架不会因为 AI 能够生成代码而消失。它真正需要完成的,是重新设计自身的抽象、工具和生态,让人和 AI 都能在一个统一、可靠的技术体系中工作。
嘉宾简介
谢国,华为鸿蒙突击队 编程框架首席技术专家
拥有 10+年移动应用开发经验,主导多个互联网开源框架,曾任字节跳动 Flutter 团队负责人。

本文来源:InfoQ