👋 你好,欢迎来到我的博客!我是【菜鸟学鸿蒙】
   我是一名在路上的移动端开发者,正从传统“小码农”转向鸿蒙原生开发的进阶之旅。为了把学习过的知识沉淀下来,也为了和更多同路人互相启发,我决定把探索 HarmonyOS 的过程都记录在这里。
  
  🛠️ 主要方向:ArkTS 语言基础、HarmonyOS 原生应用(Stage 模型、UIAbility/ServiceAbility)、分布式能力与软总线、元服务/卡片、应用签名与上架、性能与内存优化、项目实战,以及 Android → 鸿蒙的迁移踩坑与复盘。
  🧭 内容节奏:从基础到实战——小示例拆解框架认知、专项优化手记、实战项目拆包、面试题思考与复盘,让每篇都有可落地的代码与方法论。
  💡 我相信:写作是把知识内化的过程,分享是让生态更繁荣的方式。
  
   如果你也想拥抱鸿蒙、热爱成长,欢迎关注我,一起交流进步!🚀

前言:内存管理不是“省钱”,是“保命”🙂

很多人对内存的误解是:“反正有 GC 啊,怕啥?”
我只能说:兄弟你真敢😂。GC 只负责“能证明没用”的对象;但你只要还留着一根引用(哪怕你自己都忘了),它就会很认真地说:

“那我可不敢收嗷。”🙂

HarmonyOS 的 ArkTS 运行时有专门的 GC 垃圾回收机制说明(官方把 ArkTS 运行时与 GC 章节拆出来讲)。
而 OpenHarmony 的 ArkCompiler Runtime Core 也公开了更底层的内存与 GC 设计(region / G1 风格、线程 safepoint 协作等)。

下面按你大纲来:分配策略 → GC → 泄漏排查 → 优化实战,不绕弯子。

1)内存分配策略:对象都分到哪儿去了?

1.1 先把“两个堆”分清:ArkTS Heap vs Native Heap

你写 ArkTS/ArkUI 的对象(组件状态、闭包、数组、Map…)主要在 ArkTS 虚拟机堆里,由 GC 管。
但一旦你用到图片解码、媒体、NAPI/C++、三方库,Native 堆就会开始参与——这也是最容易出现“看起来 GC 很勤快,但内存还是涨”的原因(因为涨的是 Native)。

我自己排查内存时,脑子里会先问一句:
“这坨内存涨的是 ArkTS 还是 Native?”
不先分清,等于闭着眼抓贼🙃。

1.2 分代 + Region:年轻代、老年代、大对象“各有住处”

Ark 的运行时在堆管理上是分代思想 + region 化的典型路线:对象按生命周期特征分配,GC 也会按代/区域来做更高效的回收与整理。OpenHarmony 的 Runtime Core 文档直接把 GC 描述为 G1 风格、基于 region 的组织,并且涉及并发/协作的 safepoint 机制。

工程意义是啥?

  • 短命对象(比如 build 里临时 new 的数组/对象)如果太多,会让年轻代回收变频繁 → 抖动
  • 大对象(大图、大数组)如果反复创建,会造成堆压力大、搬运/整理成本高 → 卡顿/峰值高

2)垃圾回收机制:GC 不是“清理工”,它是“法官”😤

2.1 你需要知道的 3 个现实

  1. GC 不是立刻发生:它会根据堆压力/阈值/策略触发(官方在 ArkTS 运行时章节专门列了 GC 垃圾回收内容)。
  2. 可达对象不会收:只要引用链还在,它就判“有罪(不能回收)”。
  3. 并发/协作很关键:底层需要线程进入 safepoint/安全区域,才能做某些阶段的 GC(Runtime Core 里对 safepoint、线程状态协调有说明)。

2.2 “为什么我感觉卡了一下?”——常见原因

  • 回收频繁(内存抖动):短命对象太多
  • 整理/搬运成本高:大对象、多引用结构
  • UI 主线程压力大:GC 相关暂停或抢占导致可感知卡顿(尤其动画/滑动时更明显)

3)内存泄漏排查:别靠猜,靠证据(工具链要用起来)🧰

3.1 DevEco Profiler:Allocation + Snapshot(两把刀,一把定界,一把定罪)

DevEco Studio 的 Profiler 支持 Allocation(分配)、**Snapshot(快照)**等分析任务;其中 Snapshot 用来抓某时刻的内存快照并对比差异,定位“退出页面仍存活的对象”。

我常用的排查套路(超实用)

  1. 复现路径:进入页面 → 操作 10 秒 → 返回
  2. 抓快照 A(刚进入稳定后)
  3. 返回后再抓快照 B(按理该释放)
  4. 对比 A/B:如果某类对象数量/Retained Size 明显上升且不回落 → 八九不离十
    (官方 Snapshot 指导就围绕“页面跳转场景是否泄漏”来做示例)。

3.2 HiDumper:宏观确认“进程到底胖了多少”

HiDumper 是官方的系统信息导出命令行工具,支持分析 CPU、内存、存储等资源使用情况。
它特别适合做两件事:

  • 先确认“是不是进程级别真的在涨”
  • 在自动化/长时间运行场景看趋势(比 UI 工具更稳)

3.3 一个很真实的提醒:Debug 包才更好查

Snapshot 指导明确提到:需要 debug 编译模式等使用约束。
所以别拿 release 包上来就说“工具看不见”——那属于自己跟自己较劲😅。

4)优化实战:给你一套“看得见效果”的打法(含代码)🔥

下面我用 ArkUI 最常见的泄漏来做实战:

页面退出了,但对象还被全局事件/定时器/订阅持有 → GC 判“可达” → 永远不回收。

4.1 反面例子:事件订阅不解绑(经典中的经典…气人😤)

// 一个很常见的“全局事件总线”
class EventBus {
  private map: Map<string, Function[]> = new Map()
  on(topic: string, fn: Function) {
    const arr = this.map.get(topic) ?? []
    arr.push(fn)
    this.map.set(topic, arr)
  }
  off(topic: string, fn: Function) {
    const arr = this.map.get(topic) ?? []
    this.map.set(topic, arr.filter(it => it !== fn))
  }
  emit(topic: string, data?: any) {
    (this.map.get(topic) ?? []).forEach(fn => fn(data))
  }
}
export const bus = new EventBus()

@Entry
@Component
struct LeakPage {
  @State count: number = 0

  private onMsg = (v?: number) => {
    // 这个闭包会把 this(页面实例)一起“拴住”
    this.count = (v ?? 0)
  }

  aboutToAppear() {
    bus.on('tick', this.onMsg) // ❌ 注册了
  }

  // ❌ 忘了解绑:页面退了,但 bus 还握着回调 → 页面对象可达 → GC 不收
  // aboutToDisappear() { bus.off('tick', this.onMsg) }

  build() {
    Column({ space: 12 }) {
      Text(`count=${this.count}`)
      Button('模拟消息').onClick(() => bus.emit('tick', this.count + 1))
    }.padding(16)
  }
}

4.2 正确修复:生命周期“成对”处理(像刷牙一样理所当然🪥)

aboutToAppear() {
  bus.on('tick', this.onMsg)
}

aboutToDisappear() {
  bus.off('tick', this.onMsg) // ✅ 成对解绑
}

你别小看这一行 off。
很多“页面退出还涨内存”的案子,真凶就躲在这儿,还躲得特别理直气壮🙂。

4.3 再给你一套“立刻见效”的优化清单(我自己项目里常用)

  • 减少 build 中临时对象:循环里 new 大对象、拼大数组、频繁 JSON.parse 都收敛
  • 大图/媒体资源及时释放:不用就 release/close(混合栈尤其重要)
  • 缓存要有上限:Map/Array 做缓存一定要容量控制(不然缓存=泄漏的文艺说法)
  • 列表里别搞重布局动画:动 opacity/translate/scale 更友好(动 height/padding 很容易带来布局抖动)
  • 用 Snapshot 验证优化是否生效:别“我感觉好了”,要“数据说好了”

结尾:内存问题的本质,是“谁还握着谁的手不放”🙂

你最后能不能把内存搞定,核心不是背 GC 名词,而是能回答一句话:

“这个对象为什么还活着?”
用 Profiler 的 Allocation 定界、用 Snapshot 定罪、用 HiDumper 看趋势,三件套齐了,你排查会快很多。

📝 写在最后

如果你觉得这篇文章对你有帮助,或者有任何想法、建议,欢迎在评论区留言交流!你的每一个点赞 👍、收藏 ⭐、关注 ❤️,都是我持续更新的最大动力!

我是一个在代码世界里不断摸索的小码农,愿我们都能在成长的路上越走越远,越学越强!

感谢你的阅读,我们下篇文章再见~👋

✍️ 作者:某个被流“治愈”过的 移动端 老兵
📅 日期:2025-11-05
🧵 本文原创,转载请注明出处。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐