检测资源泄漏问题的方法如下表所示:
阶段 | 内存泄漏 | 句柄泄漏 | 线程泄漏 |
|---|---|---|---|
开发态 | HiDumper、DevEco Profiler、DevEco Testing | DevEco Testing | hdc shell ps命令、DevEco Testing |
运行态 | HiAppEvent | HiAppEvent | HiAppEvent |
方式二:使用DevEco Profiler检测是否存在内存泄漏问题。
启动应用,打开DevEco Profiler工具,选取应用后启动实时监控功能,执行测试步骤,查看Memory泳道应用内存变化情况,当一段时间内存不断上涨无回落或者内存占用增长多(比如达到3GB及以上),则可初步判断应用存在内存泄漏问题。

如检测应用是否存在文件句柄泄漏类问题,可参考文件句柄泄漏类问题检测方法中的检测步骤。
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);
} 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;
} export const triggerThreadLeak:() => void;
// Pss泄漏
triggerPssLeak() {
testNapi.triggerPssLeak();
} 
等待15到30分钟左右,可以看到有如下日志打印,resource_type字段为pss_memory。同一个应用,24小时内至多上报一次资源泄漏事件,测试时可以通过重启设备来实现短时间内二次上报。

// 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}`);
});
}
} 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;
} export const triggerThreadLeak:() => void;
// 线程泄漏
triggerThreadLeak() {
testNapi.triggerThreadLeak();
} 完整代码如下:
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');
}
} 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%')
}
} /*
* 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);
} export const triggerPssLeak: () => void; export const triggerThreadLeak:() => void;