鸿蒙中常见的内存泄漏有哪些?

本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

鸿蒙(HarmonyOS)开发中,内存泄漏(Memory Leak)会导致应用性能下降甚至崩溃。以下是常见泄漏场景、排查工具及解决方案的示例:

一、常见内存泄漏场景

1. 未释放的资源引用
  • 案例:未关闭文件句柄、数据库连接。
    let file = fs.openSync('data.txt', fs.OpenMode.READ_WRITE);
    // 忘记调用 fs.closeSync(file.fd);
    修复:在aboutToDisappearonDestroy中释放资源。
2. 全局变量持有组件引用
  • 案例:全局对象持有页面或组件的引用。
    let globalRef: any;
    @Component
    struct LeakyComponent {
      aboutToAppear() {
        globalRef = this; // 错误!全局变量持有组件实例
      }
    }
    修复:使用弱引用WeakRef或及时置空。
3. 事件监听未取消
  • 案例emitterrouter监听未移除。
    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. 定时器未清除
  • 案例setIntervalsetTimeout未清理。
    setInterval(() => {
      console.log('Running...'); // 页面销毁后仍执行
    }, 1000);
    修复:使用clearInterval/clearTimeout

二、内存泄漏排查工具

1. DevEco Studio内存分析器
  • 步骤
    1. 点击底部 Profiler 选项卡。
    2. 选择 Memory 并录制内存快照。
    3. 对比操作前后的对象分配情况。 
2. HiLog打印内存信息
  • 代码示例
    import { hilog } from '@kit.PerformanceAnalysisKit';
    hilog.debug(0x0000, 'Memory', '当前内存占用: %{public}d', 
      performance.getMemoryUsage().jsHeapSizeLimit);
    输出:监控关键节点的内存变化。
3. ArkTS内存快照
  • 命令行工具
    hdc shell snapshot_dump -p <pid> -o /data/local/tmp/heap.hprof
    hdc file recv /data/local/tmp/heap.hprof .
    分析:使用MAT(Memory Analyzer Tool)查看对象引用链。

三、代码层预防措施

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中的清理逻辑
内存持续增长定时器/动画未停止使用clearIntervalanimateToonFinish回调
频繁GC导致卡顿短时间创建大量临时对象使用对象池(如collections.Queue复用对象)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值