如何检测资源泄漏问题
==========

#### 问题现象

如何检测应用资源泄漏问题？

#### 背景知识

*   资源泄漏主要分为内存泄漏、句柄泄漏、线程泄漏，指句柄、线程或内存等资源在应用运行过程中未被正确释放，导致资源长期占用且无法被其他应用使用。对于每种泄漏，系统会通过周期采样的方式对进程的资源使用情况进行检测，如果资源使用超过阈值，会抓取对应维测并上报泄漏事件。资源泄漏的相关内容可查看[Resource Leak（资源泄漏）检测](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/resource-leak-guidelines)。
*   HiAppEvent是系统为应用开发者提供的事件打点机制，支持记录应用运行过程中的故障、统计、安全和行为事件，帮助开发者定位问题、分析应用运行情况，统计访问量、用户活跃度、操作习惯以及其他影响用户使用产品的关键因素，更多内容可查看[HiAppEvent介绍](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/hiappevent-intro)。
*   [DevEco Profiler](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-profiler)提供实时监控（Realtime Monitor）能力，提供全方位的设备资源监测，覆盖系统事件、异常报告、CPU占用、内存占用、实时帧率、GPU使用率、能耗以及网络流量消耗等多个维度的数据，能够结合代码进行白盒分析，明确不合理的负载出现位置，帮助识别性能瓶颈，定界问题所在，提高解决问题的效率。

#### 解决方案

检测资源泄漏问题的方法如下表所示：

| 
阶段

 | 

内存泄漏

 | 

句柄泄漏

 | 

线程泄漏

 |
| :-- | :-- | :-- | :-- |
| 

开发态

 | 

HiDumper、DevEco Profiler、DevEco Testing

 | 

DevEco Testing

 | 

hdc shell ps命令、DevEco Testing

 |
| 

运行态

 | 

HiAppEvent

 | 

HiAppEvent

 | 

HiAppEvent

 |

*   开发态检测：
    1.  有明确的测试场景：执行测试场景相应的测试步骤，通过工具或命令确认应用是否有资源泄漏问题。
        *   内存泄漏：
            
            方式一：通过hidumper命令查询是否存在内存泄漏。
            
            1.  打开应用，通过hdc shell "hidumper -s WindowManagerService -a '-a'"获取当前应用的pid，如下图中可以看到pid为7066。
                
                ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/a4/v3/rWAFjaefT66tTijQeRka4w/zh-cn_image_0000002628395024.png?HW-CC-KV=V1&HW-CC-Date=20260709T133742Z&HW-CC-Expire=86400&HW-CC-Sign=4AE8FDDB561EE1BE7FACDCE70303E795A40CCBE75506F7520C006F1FD1836779 "点击放大")
                
            2.  输入hdc shell "hidumper --mem \[pid\]"查看应用的内存信息，在测试过程观察Pss（实际使用物理内存）Total一列的数据，是否存在持续增长未回落的情况。如下图中可以看到应用占用3494411KB的内存，主要为Native堆内存（3439852KB），存在Native堆内存泄漏问题。
                
                ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/02/v3/VKrzKRWmScu4wQSbnppQtA/zh-cn_image_0000002658914243.png?HW-CC-KV=V1&HW-CC-Date=20260709T133742Z&HW-CC-Expire=86400&HW-CC-Sign=39C2D4BA9A31842396A252DDD69E8050C2DCF1A272B4248222F9EF667008AF78 "点击放大")
                
            
            方式二：使用DevEco Profiler检测是否存在内存泄漏问题。
            
            启动应用，打开DevEco Profiler工具，选取应用后启动[实时监控](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/realtime-monitor)功能，执行测试步骤，查看Memory泳道应用内存变化情况，当一段时间内存不断上涨无回落或者内存占用增长多（比如达到3GB及以上），则可初步判断应用存在内存泄漏问题。
            
            ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/c2/v3/PzuZdfcxRJKZsoug_7Hqag/zh-cn_image_0000002658794291.png?HW-CC-KV=V1&HW-CC-Date=20260709T133742Z&HW-CC-Expire=86400&HW-CC-Sign=5E6807514964810A1FCB59803AF18A88BF5E62462424B74A44716B89801D3A4F "点击放大")
            
        *   线程泄漏：
            1.  打开应用，通过hdc shell "hidumper -s WindowManagerService -a '-a'"获取当前应用的pid，如下图中可以看到pid为7066。
                
                ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/f1/v3/glVmnTcrSNiUwVXezsIhLA/zh-cn_image_0000002628554930.png?HW-CC-KV=V1&HW-CC-Date=20260709T133742Z&HW-CC-Expire=86400&HW-CC-Sign=DC97BA7C3058F91992DDE0ECC289335E0DBF37C698B9DBF3FA59669C8E93221B "点击放大")
                
            2.  通过hdc shell ps -T \[pid\]命令可以查看应用进程的线程信息，通过hdc shell "ps -T \[pid\] | wc -l"命令可以查看应用进程的线程总数，如下图中可以看到应用进程的线程总数为1619，超出了线程泄漏检测的阈值（700个）。
                
                ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/34/v3/IyuOBC2qTOK9i9rutbx4mQ/zh-cn_image_0000002628395030.png?HW-CC-KV=V1&HW-CC-Date=20260709T133742Z&HW-CC-Expire=86400&HW-CC-Sign=68F0051C6B4DBF911CE1D95B581A4562DCAB33A8C6C7B5492EE4B9E82E4F0B0C "点击放大")
                
        *   句柄泄漏：
            
            如检测应用是否存在文件句柄泄漏类问题，可参考文件句柄泄漏类问题检测方法中的[检测步骤](https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-stability-file-handle-detection#section10763954174218)。
            
    2.  无明确的测试场景：使用DevEco Testing进行[探索测试](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/other-test#section3638191433115)或[稳定性基础质量测试](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/stability-testing#section1661194962815)，检测是否存在资源泄漏问题。
*   运行态检测：可以使用HiAppEvent订阅资源泄漏事件，检测资源泄漏问题，相关开发步骤如下。
    1.  新建一个Native C++应用工程，编辑工程中的"entry > src > main > ets > entryability > EntryAbility.ets"文件，在OnCreate函数中订阅资源泄漏事件，示例代码如下：
        
        addEventWatch() {
          let watcher: hiAppEvent.Watcher = {
            _// 自定义观察者名称_
            name: 'watcher',
            _// 订阅了资源泄漏事件_
            appEventFilters: \[
              {
                domain: hiAppEvent.domain.OS,
                names: \[hiAppEvent.event.RESOURCE\_OVERLIMIT\]
              }
            \],
            _// 实现订阅实时回调函数_
            onReceive: (domain: string, appEventGroups: Array<hiAppEvent.AppEventGroup>) => {
              hilog.info(0x0000, 'testTag', \`HiAppEvent onReceive: domain=${domain}\`);
              for (const eventGroup of appEventGroups) {
                hilog.info(0x0000, 'testTag', \`HiAppEvent eventName=${eventGroup.name}\`);
                for (const eventInfo of eventGroup.appEventInfos) {
                  _// 打印资源泄漏事件的信息_
                  hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo=${JSON.stringify(eventInfo)}\`);
                }
              }
            }
          };
          let configParams: Record<string, hiAppEvent.ParamType> = {
            'js\_heap\_logtype': 'event', _// 仅获取事件_
          };
          _// 设置资源泄漏事件的自定义配置_
          hiAppEvent.setEventConfig(hiAppEvent.event.RESOURCE\_OVERLIMIT, configParams);
          hiAppEvent.addWatcher(watcher);
        }
        
    2.  构造资源泄漏场景，触发资源泄漏。
        *   JS泄漏：
            1.  编辑工程中的"entry > src > main > ets > pages > Index.ets"文件，新增triggerJsLeak函数，在函数中多次创建大数组，添加按钮并在onClick函数中调用triggerJsLeak函数。
                
                _// JS泄漏_
                triggerJsLeak() {
                  for (let i = 0; i < 100; i++) {
                    this.leakedArray.push(new Array(100000).fill(1));
                  }
                }
                
            2.  启动应用后连续点击按钮多次，应用会闪退，重新打开应用后可以看到如下日志打印，resource\_type字段为js\_heap。
                
                ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/e4/v3/WaPLO6yST9yDrNSt-pTyiQ/zh-cn_image_0000002658914247.png?HW-CC-KV=V1&HW-CC-Date=20260709T133742Z&HW-CC-Expire=86400&HW-CC-Sign=9DF38D3EAF81F8413E08D645F420F38E38E258BBF238111929D6E57DBEF3496F "点击放大")
                
        *   Pss内存泄漏：
            1.  编辑工程中"entry > src > main > cpp > napi\_init.cpp"文件，新增TriggerPssLeak函数，在函数中启动一个线程去申请内存构造Pss内存泄漏。
                
                static void AllocateSize() 
                {
                    for (int i = 0; i < 3; i++) {
                        int size = 1181116006; _// 大约1.1G字节_
                        char \*p = (char \*) malloc(size);
                        std::fill\_n(p, size, 'a');
                    }
                    OH\_LOG\_INFO(LOG\_APP, "AllocateSize");
                }
                
                static napi\_value TriggerPssLeak(napi\_env env, napi\_callback\_info info)
                {
                    size\_t argc = 2;
                    napi\_value args\[2\] = {nullptr};
                
                    napi\_get\_cb\_info(env, info, &argc, args , nullptr, nullptr);
                
                    std::thread t1(AllocateSize);
                    t1.detach();
                    return 0;
                }
                
                在初始化函数init中增加TriggerPssLeak接口映射。
                
                static napi\_value Init(napi\_env env, napi\_value exports)
                {
                    napi\_property\_descriptor desc\[\] = {
                        { "triggerPssLeak", nullptr, TriggerPssLeak, nullptr, nullptr, nullptr, napi\_default, nullptr },
                        { "triggerThreadLeak", nullptr, TriggerThreadLeak, nullptr, nullptr, nullptr, napi\_default, nullptr },
                    };
                    napi\_define\_properties(env, exports, sizeof(desc) / sizeof(desc\[0\]), desc);
                    return exports;
                }
                
            2.  在接口声明文件（entry > src > main > cpp > types > libentry > index.d.ts）中添加triggerPssLeak函数导出声明。
                
                export const triggerThreadLeak:() => void;
                
            3.  编辑工程中的"entry > src > main > ets > pages > Index.ets"文件，添加按钮并在onClick函数中调用triggerPssLeak。
                
                _// Pss泄漏_
                triggerPssLeak() {
                  testNapi.triggerPssLeak();
                }
                
            4.  启动应用后点击按钮，使用Profiler的[实时监控](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/realtime-monitor)功能，通过Memory泳道确认应用当前占用内存3.3GB。
                
                ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/b6/v3/1XsMpU_OSti8y4jhvDyUzg/zh-cn_image_0000002658794295.png?HW-CC-KV=V1&HW-CC-Date=20260709T133742Z&HW-CC-Expire=86400&HW-CC-Sign=D12C9FDAD517FAA42E9212056C485B1DB97C276CBF69FEC2BEE5C11F17090D64 "点击放大")
                
                等待15到30分钟左右，可以看到有如下日志打印，resource\_type字段为pss\_memory。同一个应用，24小时内至多上报一次资源泄漏事件，测试时可以通过重启设备来实现短时间内二次上报。
                
                ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/1a/v3/NNjgqZUDS1afBlBa1ttTqg/zh-cn_image_0000002628554932.png?HW-CC-KV=V1&HW-CC-Date=20260709T133742Z&HW-CC-Expire=86400&HW-CC-Sign=B8D36C27B5D29F5E95C1D05D6572DEF47C96CDC0FCDFAFFD3D90568EF0638CF1 "点击放大")
                
        *   Ion泄漏：
            1.  编辑工程中的"entry > src > main > ets > pages > Index.ets"文件，新增triggerIonLeak函数，创建多个像素图来构造Ion泄漏，添加按钮并在onClick函数中调用triggerIonLeak函数。
                
                _// Ion泄漏_
                triggerIonLeak() {
                  for (let i = 0; i < 4800; i++) {
                    let imageSource = image.createImageSource(this.buffer);
                    imageSource.createPixelMap().then((pixel: image.PixelMap) => {
                      pixel.setMemoryNameSync(\`leak\_image\_${i}\`);
                      this.leakedPixelMap.push(pixel);
                    }).catch((error: BusinessError) => {
                      hilog.error(DOMAIN, 'testTag', \`create pixel map ${i} failed. code is ${error.code} message is ${error.message}\`);
                    });
                  }
                }
                
            2.  启动应用后点击按钮，等待几分钟后可以看到如下日志打印，resource\_type字段为ion\_memory。如果长时间未看到相关日志打印，可以重启手机后重新执行该步骤。
                
                ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/7b/v3/XP8w20CrRBOhmVu-S6uFng/zh-cn_image_0000002628395032.png?HW-CC-KV=V1&HW-CC-Date=20260709T133742Z&HW-CC-Expire=86400&HW-CC-Sign=AA245410C3665AB8CDFAB6073DF9F0DD921FC522D91A68962E56BB13E77D7AD3 "点击放大")
                
        *   句柄泄漏：
            1.  编辑工程中的"entry > src > main > ets > pages > Index.ets"文件，新增triggerFdLeak函数，打开多个文件来构造句柄泄漏，添加按钮并在onClick函数中调用triggerFdLeak函数。
                
                _// Fd泄漏_
                triggerFdLeak() {
                  let filesDir = this.getUIContext().getHostContext()?.filesDir ?? '';
                  for (let i = 0; i < 32768; i++) {
                    let path = filesDir + '/leakFile.txt';
                    fileIo.open(path, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ\_WRITE)
                      .then((file: fileIo.File)=> {
                        this.leakedFds.push(file.fd);
                      })
                      .catch((error: BusinessError) => {
                        hilog.error(DOMAIN, 'testTag', \`open ${path} failed. code is ${error.code} message is ${error.message}\`);
                      });
                  }
                }
                
            2.  启动应用后点击按钮，等待几分钟后运行hdc shell ls -l /data/log/reliability/resource\_leak/fd\_leak命令查看是否有应用进程的句柄泄漏日志生成（文件名为进程pid\_fd\_leak.txt）。如果有日志生成，将应用退出后重启，可以看到有如下日志打印，resource\_type字段为fd；如果长时间未看到句柄泄漏日志生成，可以重启手机后重新执行该步骤。
                
                ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/7b/v3/Ucg4n5_URQyQyQubOpXViQ/zh-cn_image_0000002658914249.png?HW-CC-KV=V1&HW-CC-Date=20260709T133742Z&HW-CC-Expire=86400&HW-CC-Sign=E172A1B667CC744D0142733FB7CB1F086A77E7D23E5EC9EDA895287747149242 "点击放大")
                
        *   线程泄漏：
            1.  编辑工程中"entry > src > main > cpp > napi\_init.cpp"文件，新增TriggerThreadLeak函数，启动多个线程构造线程泄漏。
                
                void\* ThreadLeakFun(void\*)
                {
                    while(1) {
                        std::this\_thread::sleep\_for(std::chrono::milliseconds(500));
                    }
                }
                
                static napi\_value TriggerThreadLeak(napi\_env env, napi\_callback\_info info)
                {
                    size\_t argc = 2;
                    napi\_value args\[2\] = {nullptr};
                
                    napi\_get\_cb\_info(env, info, &argc, args , nullptr, nullptr);
                
                    for(int i = 0; i < 1600; i++) {
                        pthread\_t thread;
                        pthread\_create(&thread, NULL, ThreadLeakFun, NULL);
                    }
                    OH\_LOG\_INFO(LOG\_APP, "TriggerThreadLeak");
                    return 0;
                }
                
                在初始化函数init中增加TriggerThreadLeak接口映射。
                
                static napi\_value Init(napi\_env env, napi\_value exports)
                {
                    napi\_property\_descriptor desc\[\] = {
                        { "triggerPssLeak", nullptr, TriggerPssLeak, nullptr, nullptr, nullptr, napi\_default, nullptr },
                        { "triggerThreadLeak", nullptr, TriggerThreadLeak, nullptr, nullptr, nullptr, napi\_default, nullptr },
                    };
                    napi\_define\_properties(env, exports, sizeof(desc) / sizeof(desc\[0\]), desc);
                    return exports;
                }
                
            2.  在接口声明文件（entry > src > main > cpp > types > libentry > index.d.ts）中添加triggerThreadLeak函数导出声明。
                
                export const triggerThreadLeak:() => void;
                
            3.  编辑工程中的"entry > src > main > ets > pages > Index.ets"文件，添加按钮并在onClick函数中调用triggerThreadLeak。
                
                _// 线程泄漏_
                triggerThreadLeak() {
                  testNapi.triggerThreadLeak();
                }
                
            4.  启动应用后点击按钮，等待几分钟后可以看到有如下日志打印，resource\_type字段为thread。如果长时间未看到相关日志打印，可以重启手机后重新执行该步骤。
                
                ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/43/v3/f84_doRrSwOYOMGstSKqyw/zh-cn_image_0000002658794297.png?HW-CC-KV=V1&HW-CC-Date=20260709T133742Z&HW-CC-Expire=86400&HW-CC-Sign=85FCB66B5C5635144ED0A4D2EB273A342E29F4FE3B7CB91311AEA3275074E9C8 "点击放大")
                

完整代码如下：

*   EntryAbility.ets文件：
    
    import { ConfigurationConstant, UIAbility } from '@kit.AbilityKit';
    import { hiAppEvent, hilog } from '@kit.PerformanceAnalysisKit';
    import { window } from '@kit.ArkUI';
    
    const DOMAIN = 0x0000;
    
    export default class EntryAbility extends UIAbility {
      onCreate(): void {
        try {
          this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR\_MODE\_NOT\_SET);
        } catch (err) {
          hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
        }
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
        this.addEventWatch();
      }
    
      addEventWatch() {
        let watcher: hiAppEvent.Watcher = {
          _// 自定义观察者名称_
          name: 'watcher',
          _// 订阅了资源泄漏事件_
          appEventFilters: \[
            {
              domain: hiAppEvent.domain.OS,
              names: \[hiAppEvent.event.RESOURCE\_OVERLIMIT\]
            }
          \],
          _// 实现订阅实时回调函数_
          onReceive: (domain: string, appEventGroups: Array<hiAppEvent.AppEventGroup>) => {
            hilog.info(0x0000, 'testTag', \`HiAppEvent onReceive: domain=${domain}\`);
            for (const eventGroup of appEventGroups) {
              hilog.info(0x0000, 'testTag', \`HiAppEvent eventName=${eventGroup.name}\`);
              for (const eventInfo of eventGroup.appEventInfos) {
                _// 打印资源泄漏事件的信息_
                hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo=${JSON.stringify(eventInfo)}\`);
              }
            }
          }
        };
        let configParams: Record<string, hiAppEvent.ParamType> = {
          'js\_heap\_logtype': 'event', _// 仅获取事件_
        };
        _// 设置资源泄漏事件的自定义配置_
        hiAppEvent.setEventConfig(hiAppEvent.event.RESOURCE\_OVERLIMIT, configParams);
        hiAppEvent.addWatcher(watcher);
      }
    
      onDestroy(): void {
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
      }
    
      onWindowStageCreate(windowStage: window.WindowStage): void {
        _// Main window is created, set main page for this ability_
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
    
        windowStage.loadContent('pages/Index', (err) => {
          if (err.code) {
            hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
            return;
          }
          hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
          windowStage.getMainWindow().then((win: window.Window) => {
            win.setWindowKeepScreenOn(true);
          });
        });
      }
    
      onWindowStageDestroy(): void {
        _// Main window is destroyed, release UI related resources_
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
      }
    
      onForeground(): void {
        _// Ability has brought to foreground_
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
      }
    
      onBackground(): void {
        _// Ability has back to background_
        hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
      }
    }
    
*   Index.ets文件：
    
    import testNapi from 'libentry.so';
    import { image } from '@kit.ImageKit';
    import { BusinessError } from '@kit.BasicServicesKit';
    import { fileIo } from '@kit.CoreFileKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    
    const DOMAIN = 0x0000;
    
    @Entry
    @Component
    struct Index {
      private buffer?: ArrayBuffer;
    
      private leakedArray: Array<number\[\]> = \[\];
    
      private leakedPixelMap: Array<image.PixelMap> = \[\];
    
      private leakedFds: number\[\] = \[\];
    
      aboutToAppear(): void {
        let resourceManager = this.getUIContext().getHostContext()?.resourceManager;
        if (resourceManager) {
          resourceManager.getMediaByName('background').then((value: Uint8Array) => {
            this.buffer = value.buffer.slice(0);
          });
        }
      }
    
      _// JS泄漏_
      triggerJsLeak() {
        for (let i = 0; i < 100; i++) {
          this.leakedArray.push(new Array(100000).fill(1));
        }
      }
    
      _// Pss泄漏_
      triggerPssLeak() {
        testNapi.triggerPssLeak();
      }
    
      _// Ion泄漏_
      triggerIonLeak() {
        for (let i = 0; i < 4800; i++) {
          let imageSource = image.createImageSource(this.buffer);
          imageSource.createPixelMap().then((pixel: image.PixelMap) => {
            pixel.setMemoryNameSync(\`leak\_image\_${i}\`);
            this.leakedPixelMap.push(pixel);
          }).catch((error: BusinessError) => {
            hilog.error(DOMAIN, 'testTag', \`create pixel map ${i} failed. code is ${error.code} message is ${error.message}\`);
          });
        }
      }
    
      _// Fd泄漏_
      triggerFdLeak() {
        let filesDir = this.getUIContext().getHostContext()?.filesDir ?? '';
        for (let i = 0; i < 32768; i++) {
          let path = filesDir + '/leakFile.txt';
          fileIo.open(path, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ\_WRITE)
            .then((file: fileIo.File)=> {
              this.leakedFds.push(file.fd);
            })
            .catch((error: BusinessError) => {
              hilog.error(DOMAIN, 'testTag', \`open ${path} failed. code is ${error.code} message is ${error.message}\`);
            });
        }
      }
    
      _// 线程泄漏_
      triggerThreadLeak() {
        testNapi.triggerThreadLeak();
      }
    
      build() {
        Column() {
          Button('Js Leak')
            .margin({
              top: 20
            })
            .onClick(() => {
              _// 点击几下即可触发应用崩溃，然后重启_
              this.triggerJsLeak();
            })
    
          Button('Pss Leak')
            .margin({
              top: 20
            })
            .onClick(() => {
              this.triggerPssLeak();
            })
    
          Button('Ion Leak')
            .margin({
              top: 20
            })
            .onClick(() => {
              this.triggerIonLeak();
            })
    
          Button('Fd Leak')
            .margin({
              top: 20
            })
            .onClick(() => {
              _// 重启后点击该按钮, 如出现fd\_leak泄漏日志后重启应用, 等待一段时间后可触发_
              this.triggerFdLeak();
            })
    
          Button('Thread Leak')
            .margin({
              top: 20
            })
            .onClick(() => {
              _// 点击该按钮, 等待一段时间后可触发_
              this.triggerThreadLeak();
            })
        }
        .height('100%')
        .width('100%')
      }
    }
    
*   napi\_init.cpp文件：
    
    _/\*_
     _\* Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved._
     _\*/_
    
    #include "napi/native\_api.h"
    #include <cstdlib>
    #include <hilog/log.h>
    #include <thread>
    
    static void AllocateSize() 
    {
        for (int i = 0; i < 3; i++) {
            int size = 1181116006; _// 大约1.1G字节_
            char \*p = (char \*) malloc(size);
            std::fill\_n(p, size, 'a');
        }
        OH\_LOG\_INFO(LOG\_APP, "AllocateSize");
    }
    
    static napi\_value TriggerPssLeak(napi\_env env, napi\_callback\_info info)
    {
        size\_t argc = 2;
        napi\_value args\[2\] = {nullptr};
    
        napi\_get\_cb\_info(env, info, &argc, args , nullptr, nullptr);
    
        std::thread t1(AllocateSize);
        t1.detach();
        return 0;
    }
    
    void\* ThreadLeakFun(void\*)
    {
        while(1) {
            std::this\_thread::sleep\_for(std::chrono::milliseconds(500));
        }
    }
    
    static napi\_value TriggerThreadLeak(napi\_env env, napi\_callback\_info info)
    {
        size\_t argc = 2;
        napi\_value args\[2\] = {nullptr};
    
        napi\_get\_cb\_info(env, info, &argc, args , nullptr, nullptr);
    
        for(int i = 0; i < 1600; i++) {
            pthread\_t thread;
            pthread\_create(&thread, NULL, ThreadLeakFun, NULL);
        }
        OH\_LOG\_INFO(LOG\_APP, "TriggerThreadLeak");
        return 0;
    }
    
    EXTERN\_C\_START
    static napi\_value Init(napi\_env env, napi\_value exports)
    {
        napi\_property\_descriptor desc\[\] = {
            { "triggerPssLeak", nullptr, TriggerPssLeak, nullptr, nullptr, nullptr, napi\_default, nullptr },
            { "triggerThreadLeak", nullptr, TriggerThreadLeak, nullptr, nullptr, nullptr, napi\_default, nullptr },
        };
        napi\_define\_properties(env, exports, sizeof(desc) / sizeof(desc\[0\]), desc);
        return exports;
    }
    EXTERN\_C\_END
    
    static napi\_module demoModule = {
        .nm\_version = 1,
        .nm\_flags = 0,
        .nm\_filename = nullptr,
        .nm\_register\_func = Init,
        .nm\_modname = "entry",
        .nm\_priv = ((void\*)0),
        .reserved = { 0 },
    };
    
    extern "C" \_\_attribute\_\_((constructor)) void RegisterEntryModule(void)
    {
        napi\_module\_register(&demoModule);
    }
    
*   Index.d.ts文件：
    
    export const triggerPssLeak: () => void;
    export const triggerThreadLeak:() => void;