Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KeepAlive + Transition + v-if 同时使用时会导致时会导致内存泄漏的2个bug #10620

Closed
wcldyx opened this issue Mar 31, 2024 · 6 comments · Fixed by #10632 or #10832
Closed
Labels
🐞 bug Something isn't working scope: transition

Comments

@wcldyx
Copy link

wcldyx commented Mar 31, 2024

Vue version

3.4.21

Link to minimal reproduction

https://stackblitz.com/edit/vitejs-vite-futfv6?file=src%2FApp.vue

Steps to reproduce

测试的时候注意自己创建一个新项目测试,因为stackblitz上看内存占用不方便

有两个bug

第一个bug: KeepAlive + Transition + v-if 同时使用时会导致时会导致内存泄漏。

如图所示,通过点击toggle按钮用v-if 不停的切换显示隐藏组件,你会看到内存一直没有被释放。

image
动画1

单独使用KeepAlive 时在通过v-if隐藏组件时内存会自动释放。

动画2

第二个bug: 在 mode="out-in"时通过v-if切换并同时移除include里面的key时,对应的组件没有被正常卸载(没有触发onUnmounted), 内存也没有得到释放。

mode为默认值时,组件能正常卸载

动画3

mode="out-in" 时,组件没有被正常卸载

动画4

What is expected?

修复以上bug

What is actually happening?

KeepAlive + Transition + v-if 同时使用时会导致时会导致内存泄漏,同时在 Transition 的 mode="out-in"时,组件没有被正常卸载或销毁

System Info

No response

Any additional comments?

No response

以下是完整代码

<script lang="ts" setup>
import { ref, defineComponent, h, onUnmounted } from 'vue';
// import A from "./A.vue";

const show = ref(true);
const include = ref(['A']);

const A = defineComponent({
  name: 'A',
  setup() {
    const list = ref(new Array(1000000).fill({ name: 'hello' }));
    console.log('安装');
    onUnmounted(() => {
      console.log('卸载');
    });
    return () => h('h1', 'A组件' + list.value.length);
  },
});

function toggle() {
  show.value = !show.value;
  if (show.value) {
    include.value = ['A'];
  } else {
    include.value = [];
  }
}
</script>
<template>
  <div>include:{{ include }}</div>
  <button @click="toggle">toggle</button>
  <Transition mode="out-in">
    <KeepAlive :include="include">
      <A v-if="show" />
    </KeepAlive>
  </Transition>
</template>
@edison1105 edison1105 added 🐞 bug Something isn't working scope: transition labels Apr 1, 2024
@edison1105
Copy link
Member

edison1105 commented Apr 1, 2024

第一个问题的复现是把 mode 和 include 都去掉吗?

  <Transition>
    <KeepAlive>
      <A v-if="show" />
    </KeepAlive>
  </Transition>

image
把 mode 和 include 都去掉后,不停切换并不存在内存泄漏

@wcldyx
Copy link
Author

wcldyx commented Apr 2, 2024

第一个问题的复现是把 mode 和 include 都去掉吗?

  <Transition>
    <KeepAlive>
      <A v-if="show" />
    </KeepAlive>
  </Transition>

image 把 mode 和 include 都去掉后,不停切换并不存在内存泄漏

两个问题都是在有include 的情况下会出现内存溢出

@edison1105
Copy link
Member

@wcldyx 这是因为在开发环境会在元素上定义 __vnode,公开给 vue-devtools 使用。生产环境不会内存溢出

if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
Object.defineProperty(el, '__vnode', {
value: vnode,
enumerable: false,
})
Object.defineProperty(el, '__vueParentComponent', {
value: parentComponent,
enumerable: false,
})
}

@wcldyx
Copy link
Author

wcldyx commented Apr 3, 2024

@wcldyx 这是因为在开发环境会在元素上定义 __vnode,公开给 vue-devtools 使用。生产环境不会内存溢出

if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
Object.defineProperty(el, '__vnode', {
value: vnode,
enumerable: false,
})
Object.defineProperty(el, '__vueParentComponent', {
value: parentComponent,
enumerable: false,
})
}

6啊,你是怎么定位到这个问题的

@edison1105
Copy link
Member

@wcldyx
image
类似的问题已经有人提了好多次了。

@wcldyx wcldyx closed this as completed Apr 5, 2024
@edison1105
Copy link
Member

edison1105 commented Apr 6, 2024

Leave it open because the second issue has not been fixed

@edison1105 edison1105 reopened this Apr 6, 2024
edison1105 added a commit to edison1105/vuejs-core that referenced this issue Apr 29, 2024
yyx990803 pushed a commit that referenced this issue Apr 29, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Apr 30, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
🐞 bug Something isn't working scope: transition
Projects
None yet
2 participants