Skip to content

iframe 沙箱 capture 事件监听器清理不完整导致内存持续增长 #1708

Description

@JOJOland123

环境信息

  • micro-app:1.0.0-rc.31
  • 基座应用:Vue 3 + Vite
  • 子应用:Vue 3 + Vite
  • 沙箱模式:iframe
  • 浏览器:基于 Chromium 的 Edge / Chrome

问题描述

在多个子应用之间反复切换并卸载子应用后,即使子应用已经销毁,浏览器内存和事件监听器数量仍然持续增长。

我们的基座确实调用了 microApp.unmountApp(name, { destroy: true }),子应用 Vue 实例的 unmount 生命周期也会执行,iframe 节点也会被移除。但绑定在基座 document 上的部分事件监听器仍然存在,并继续持有旧子应用的 DOM 和 Vue 对象。

复现步骤

  1. 使用 Vue 3 + Vite 基座,开启 iframe 沙箱和 keep-alive="true"
  2. 打开一个会注册 document/window 事件的子应用,例如 clickscroll
  3. 切换到另一个子应用。
  4. 调用 microApp.unmountApp(childName, { destroy: true })
  5. 重复上述步骤多次。
  6. 强制 GC 后检查 Memory.getDOMCounters() 和 document 事件监听器。

在我们的生产规模应用中,每次循环大约残留 5,300 个 DOM 节点和 2,500 个事件监听器。循环 6 次后,即使强制 GC,JavaScript 堆仍增加了 100 MB 以上。

初步定位

沙箱效果清理逻辑注册监听器时传入了 options 对象,其中可能包含 capture: true,但清理时没有传入相同的 capture 值。例如:

rawAddEventListener.call(target, type, handler, options)
rawRemoveEventListener.call(target, type, handler)

建议清理时传回原始监听器配置:

rawRemoveEventListener.call(target, type, handler, listener.__MICRO_APP_MARK_OPTIONS__)

我们在 createProxyDocumentpatchWindowEffectpatchWindowEffect$1patchDocumentEffect 四处清理逻辑中应用了这个修改。修改后,重复卸载和重新加载 6 次,DOM 节点稳定在 14,800 个,事件监听器稳定在 3,166 个。

相关 Issue

这个问题可能与 #1017#1030#1691 有关,但本 Issue 提供了具体的监听器残留复现数据和疑似修复方案。

请维护者确认这个清理行为是否符合预期,并考虑在后续版本中修复。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions