本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
鸿蒙(HarmonyOS)开发中,内存泄漏(Memory Leak)会导致应用性能下降甚至崩溃。以下是常见泄漏场景、排查工具及解决方案的示例:
一、常见内存泄漏场景
1. 未释放的资源引用
- 案例:未关闭文件句柄、数据库连接。
修复:在let file = fs.openSync('data.txt', fs.OpenMode.READ_WRITE); // 忘记调用 fs.closeSync(file.fd);
aboutToDisappear
或onDestroy
中释放资源。
2. 全局变量持有组件引用
- 案例:全局对象持有页面或组件的引用。
修复:使用弱引用let globalRef: any; @Component struct LeakyComponent { aboutToAppear() { globalRef = this; // 错误!全局变量持有组件实例 } }
WeakRef
或及时置空。
3. 事件监听未取消
- 案例:
emitter
或router
监听未移除。
修复:在emitter.on(1001, this.callback); // 页面销毁时未取消
aboutToDisappear
中调用emitter.off(1001)
。
4. 闭包循环引用
- 案例:闭包捕获外部变量导致无法释放。
function createLeak() { let data = new Array(1000).fill('data'); return () => console.log(data.length); // 闭包持有data引用 } let leakyFunc = createLeak();
5. 定时器未清除
- 案例:
setInterval
或setTimeout
未清理。
修复:使用setInterval(() => { console.log('Running...'); // 页面销毁后仍执行 }, 1000);
clearInterval
/clearTimeout
。
二、内存泄漏排查工具
1. DevEco Studio内存分析器
- 步骤:
- 点击底部 Profiler 选项卡。
- 选择 Memory 并录制内存快照。
- 对比操作前后的对象分配情况。
2. HiLog打印内存信息
- 代码示例:
输出:监控关键节点的内存变化。import { hilog } from '@kit.PerformanceAnalysisKit'; hilog.debug(0x0000, 'Memory', '当前内存占用: %{public}d', performance.getMemoryUsage().jsHeapSizeLimit);
3. ArkTS内存快照
- 命令行工具:
分析:使用MAT(Memory Analyzer Tool)查看对象引用链。hdc shell snapshot_dump -p <pid> -o /data/local/tmp/heap.hprof hdc file recv /data/local/tmp/heap.hprof .
三、代码层预防措施
1. 生命周期管理
- 在
aboutToDisappear
中释放资源:@Component struct SafeComponent { private timer: number | undefined; aboutToAppear() { this.timer = setInterval(() => {}, 1000); } aboutToDisappear() { if (this.timer) clearInterval(this.timer); } }
2. 使用弱引用(WeakRef)
- 避免强引用导致对象无法回收:
let weakRef = new WeakRef<MyComponent>(this); let component = weakRef.deref(); // 获取对象(可能为undefined)
3. 资源释放工具类
- 封装统一释放逻辑:
class ResourceManager { private resources: Set<{ dispose: () => void }> = new Set(); add(resource: { dispose: () => void }) { this.resources.add(resource); } releaseAll() { this.resources.forEach(res => res.dispose()); this.resources.clear(); } }
四、高级排查技巧
1. 重复操作压力测试
- 反复执行可疑操作(如页面跳转),观察内存是否持续增长。
2. 对象分配追踪
- 在
build-profile.json5
中开启详细日志:{ "arkOptions": { "runtimeLog": { "level": "debug", "tag": "GC" } } }
3. 使用@Track
装饰器
- 标记可能泄漏的对象:
@Track class SuspectClass { private data = new Array(10000); }
- 原理:被
@Track
修饰的类或方法会在运行时生成日志,记录其创建、销毁和调用过程。 - 通过日志观察对象的生命周期是否异常(如未被销毁)。
五、常见问题与解决
现象 | 可能原因 | 解决方案 |
---|---|---|
页面返回后内存未释放 | 全局事件监听未取消 | 检查aboutToDisappear 中的清理逻辑 |
内存持续增长 | 定时器/动画未停止 | 使用clearInterval 或animateTo 的onFinish 回调 |
频繁GC导致卡顿 | 短时间创建大量临时对象 | 使用对象池(如collections.Queue 复用对象) |