android 下 computed变量在页面销毁时没有进行回收导致内存泄露的uni-app问题

android 下 computed变量在页面销毁时没有进行回收导致内存泄露的uni-app问题

开发环境 版本号 项目创建方式
Mac 15.6.1 (24G90) HBuilderX

产品分类:uni-app x/App

PC开发环境操作系统:Mac

HBuilderX类型:Alpha

HBuilderX版本号:4.81

手机系统:Android

手机系统版本号:Android 16

手机厂商:模拟器

手机机型:36.1.9-13823996

页面类型:nvue

vue版本:vue3

打包方式:离线

项目创建方式:HBuilderX


操作步骤:

  • 使用 computed,通过 redirectTo 销毁页面

预期结果:

  • 应该在销毁前进行 computed 的垃圾回收,避免出现内存泄露

实际结果:

┬───  
│ GC Root: Thread object  
│  
├─ android.os.HandlerThread instance  
│    Leaking: NO (PathClassLoader↓ is not leaking)  
│    Thread name: 'LeakCanary-Heap-Dump'  
│    ↓ Thread.contextClassLoader  
├─ dalvik.system.PathClassLoader instance  
│    Leaking: NO (InternalLeakCanary↓ is not leaking and A ClassLoader is never leaking)  
│    ↓ ClassLoader.runtimeInternalObjects  
├─ java.lang.Object[] array  
│    Leaking: NO (InternalLeakCanary↓ is not leaking)  
│    ↓ Object[554]  
├─ leakcanary.internal.InternalLeakCanary class  
│    Leaking: NO (UniPortraitPageActivity↓ is not leaking and a class is never leaking)  
│    ↓ static InternalLeakCanary.resumedActivity  
├─ io.dcloud.uniapp.appframe.activity.UniPortraitPageActivity instance  
│    Leaking: NO (Activity#mDestroyed is false)  
│    mApplication instance of io.dcloud.uniapp.UniApplication  
│    mBase instance of androidx.appcompat.view.ContextThemeWrapper  
│    ↓ UniPageActivity.page  
│                      ~~~~  
├─ io.dcloud.uniapp.appframe.a instance  
│    Leaking: UNKNOWN  
│    Retaining 3.9 kB in 114 objects  
│    C instance of io.dcloud.uniapp.appframe.activity.UniPortraitPageActivity with mDestroyed = false  
│    ↓ a.p  
│        ~  
├─ io.dcloud.uniapp.dom.UniNativeDocumentImpl instance  
│    Leaking: UNKNOWN  
│    Retaining 22.7 MB in 503465 objects  
│    ↓ UniNativeDocumentImpl.calculatedCallback  
│                            ~~~~~~~~~~~~~~~~~~  
├─ io.dcloud.uniapp.framework.IndexKt$$ExternalSyntheticLambda48 instance  
│    Leaking: UNKNOWN  
│    Retaining 22.5 MB in 499985 objects  
│    ↓ IndexKt$$ExternalSyntheticLambda48.f$0  
│                                         ~~~  
├─ io.dcloud.uniapp.framework.extapi.IndexKt$$ExternalSyntheticLambda33 instance  
│    Leaking: UNKNOWN  
│    Retaining 22.5 MB in 499984 objects  
│    ↓ IndexKt$$ExternalSyntheticLambda33.f$0  
│                                         ~~~  
├─ uni.UNI0B065E9.GenPagesCbtMoodChoose instance  
│    Leaking: UNKNOWN  
│    Retaining 22.5 MB in 499983 objects  
│    ↓ Page.$nativePage  
│           ~~~~~~~~~~~  
├─ io.dcloud.uniapp.appframe.a instance  
│    Leaking: UNKNOWN  
│    Retaining 929 B in 27 objects  
│    ↓ a.O  
│        ~  
├─ io.dcloud.uniapp.appframe.ui.PageFrameView instance  
│    Leaking: YES (View.mContext references a destroyed activity)  
│    Retaining 16.6 kB in 181 objects  
│    View not part of a window view hierarchy  
│    View.mAttachInfo is null (view detached)  
│    View.mID = R.id.null  
│    View.mWindowAttachCount = 1  
│    mContext instance of io.dcloud.uniapp.appframe.activity.UniPortraitPageActivity with mDestroyed = true  
│    ↓ View.mContext  
╰→ io.dcloud.uniapp.appframe.activity.UniPortraitPageActivity instance  
​     Leaking: YES (ObjectWatcher was watching this because io.dcloud.uniapp.appframe.activity.UniPortraitPageActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)  
​     Retaining 76.6 kB in 1370 objects  
​     key = 33c56a99-5d1c-47f3-925f-83289c3e16e8  
​     watchDurationMillis = 6857  
​     retainedDurationMillis = 1855  
​     mApplication instance of io.dcloud.uniapp.UniApplication  
​     mBase instance of androidx.appcompat.view.ContextThemeWrapper

更多关于android 下 computed变量在页面销毁时没有进行回收导致内存泄露的uni-app问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

更多关于android 下 computed变量在页面销毁时没有进行回收导致内存泄露的uni-app问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html


这是一个典型的 uni-app 页面销毁时 computed 变量未正确释放导致的内存泄漏问题。

从泄漏堆栈分析可以看出:

  • 泄漏根源是 UniNativeDocumentImpl.calculatedCallback 持有对页面的引用
  • 页面通过 redirectTo 导航后,虽然 Activity 已销毁(mDestroyed = true),但 computed 相关的回调函数仍然保持对页面上下文的强引用
  • 导致 22.5 MB 内存无法被垃圾回收

解决方案:

  1. 在页面 onUnload 生命周期中手动清理 computed 依赖
onUnload() {
  // 手动清理 computed 相关的响应式依赖
  this.$scope.$destroy()
}
  1. 检查 computed 函数中是否存在闭包引用 确保 computed 函数没有引用外部变量或 DOM 元素,特别是避免在 computed 中直接操作页面元素。

  2. 使用 weakRef 优化 对于可能引起循环引用的场景,考虑使用 WeakRef 来持有页面引用。

  3. 临时规避方案 在调用 redirectTo 前,可以尝试先重置页面的 computed 数据:

// 跳转前清理
this.someComputedData = null
uni.redirectTo({ url: '/pages/target' })
回到顶部