一、背景
在鸿蒙开发中,内存泄漏会直接导致鸿蒙应用持续卡顿直至崩溃闪退,并且会因占用系统资源而拖慢整个设备、增加耗电。以下是我遇到的场景及解决示例,若有其他的场景欢迎补充
二、常见内存泄漏场景及解决方案
2.1、弹窗控制器未正确释放
在aboutToDisappear 中将弹窗引用置为 null
原因:CustomDialogController 可能持有组件上下文或其他资源引用,组件销毁时若不主动释放,可能导致这些资源无法被垃圾回收,造成内存泄漏。手动置为 null 可切断引用链,帮助释放资源。
示例代码:
@Entry
@Component
struct Index {
// 在自定义组件即将析构销毁时将dialogController置空
aboutToDisappear() {
if (this.dialogController) {
this.dialogController.close(); // ✅ 先确保弹窗关闭
this.dialogController = null; // ✅ 再释放引用
}
}
dialogController: CustomDialogController | null = new CustomDialogController({
builder: CustomDialogExample({
cancel: () => {
console.info('Callback when the first button is clicked');
},
confirm: () => {
console.info('Callback when the second button is clicked');
}
}),
customStyle: true,
alignment: DialogAlignment.Bottom,
autoCancel: true,
maskColor: '#808080',
})
build() {
Column() {
Button('click me')
.onClick(() => {
if (this.dialogController != null) {
this.dialogController.open();
}
}).backgroundColor(0x317aff)
}.width('100%').margin({ top: 5 })
}
}
@CustomDialog
struct CustomDialogExample {
controller?: CustomDialogController;
cancel: () => void = () => {
}
confirm: () => void = () => {
}
build() {
Column() {
Text('可展示在主窗口外的弹窗')
.fontSize(30)
.height(100)
Button('点我关闭弹窗')
.onClick(() => {
if (this.controller != undefined) {
this.controller.close();
}
})
.margin(20)
}
}
}
2.2、事件监听器未移除
在 aboutToDisappear 中调用 getContext().eventHub.off('xxx'),移除对全局事件总线的监听
作用:避免组件销毁后仍监听事件,导致事件总线持续持有组件引用,同时防止后续事件触发时执行已销毁组件的回调逻辑(可能引发错误或内存泄漏)
@Component
struct MyComponent {
aboutToAppear() {
getContext().eventHub.on('update', this.updateHandler);
}
aboutToDisappear() {
getContext().eventHub.off('update'); // 关键:移除监听
}
private updateHandler = (data: any) => {
// 处理逻辑
}
}
2.3、 全局监听器未注销
在onWindowStageDestroy中释放全局事件监听和资源
取消网络状态监听:调用 NetworkStatus.unregister() 注销网络状态监听,避免网络模块长期持有能力上下文引用。
onWindowStageDestroy(): void {
//取消订阅默认网络状态变化的通知
NetworkStatus.unregister()
errorManager?.off('error', registerId, (err) => {
if (err) {
logger.error(`errorManager err: ${JSON.stringify(err)}`)
}
})
}
2.4、页面共享数据未清理
页面销毁时清理共享存储数据
在 uiObserver 的 routerPageUpdate 回调中,针对页面 ABOUT_TO_DISAPPEAR 状态:
调用 AppStorage.delete(key) 清除当前页面在共享存储中缓存的所有数据(如 keyOfPageInfo、keyOfPageTime 等)。
目的:页面销毁后,其关联的业务数据(如页面信息、时间戳、曝光事件集合)不再占用内存,切断存储对页面数据的引用链。
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Index', (err) => {
windowStage.getMainWindow((err: BusinessError, data)=>{
let windowInfo: window.Window = data;
if (!windowInfo?.getUIContext()) {
return
}
uiObserver.on('routerPageUpdate',windowInfo.getUIContext(),(info: uiObserver.RouterPageInfo)=>{
if (info.state == uiObserver.RouterPageState.ABOUT_TO_DISAPPEAR){
// 关键清理操作 - 防止内存泄漏
AppStorage.delete(keyOfPageInfo) // 删除页面信息
AppStorage.delete(keyOfPageTime) // 删除时间信息
AppStorage.delete(keyOfPageNewlyOpen) // 删除页面状态
AppStorage.delete(keyOfPageEventValues) // 删除事件参数
AppStorage.delete(keyOfPageReportedExposeEvent) // 删除曝光记录
}
})
})
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.');
});
}
2.5、定时器未清理
@Component
struct TimerComponent {
private timerId: number = 0;
aboutToAppear() {
this.timerId = setInterval(() => {
// 定时任务
}, 1000);
}
aboutToDisappear() {
// 必须清理定时器
clearInterval(this.timerId);
}
}
三、内存泄漏排查工具
- DevEco Studio性能分析器
- 内存快照对比
- 重复操作压力测试

被折叠的 条评论
为什么被折叠?



