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

RouterView with Transition leads to memory leak and detached nodes #2437

Open
acordy opened this issue Jan 13, 2025 · 2 comments
Open

RouterView with Transition leads to memory leak and detached nodes #2437

acordy opened this issue Jan 13, 2025 · 2 comments

Comments

@acordy
Copy link

acordy commented Jan 13, 2025

Reproduction

https://play.vuejs.org/#eNq9Vl1v2zYU/SuE+mAHiyQ3LfqguUXaIUA2rMvQZXuZ9kBLtM1EIgmSUhwY/u87JPXl1AnQhzaBE+l+HJ57eC/pfVRTLpI7E2URr5XUluxJoRm17KNS5EDWWtZk1jZsloshQMvGMj14kzQYxhCX2/uoUknIz8WAPMfnLBeEJI1h85Ae3mvZCDufvULa7Cw6j7p08FuaQnNliWG2UaSiYvM+j6zJow8Tal881D+cPUzJxwPBZRpQkIMXy2pVgRHeCFlOctvYVNICf09+kcAWTFhy8EsR/CxvNRWGWy4FEbRmCFzTkg1+RBRDWsYN/ANMHpG0h0lHnEAhHTnAsEwnBPFq7GPlHhO3WAwspmNaWN6y895YMdqyzkj2DtMOS2REKlpw+0guFova/JyLw/NpSvZJdGVkBVYh/nh1p/CTta0MAN1aGVmERCjf0ceuhv1I7Im++8xqqR+vubH4d94Zgyynt3TY/WtZM797fev1hq7/+uZcIfMobrAMjcp2PrSQwti+3d8fcZn7IreBZnaK+/wMypCQbTLyb9jzPVHUbjMyS2corm+KbCR/8FnTQOroHUePNYTw//D3gAGCtNOiv21qfufi/pTE2L+XxqbkLeElUK9vPl+NIzLBtBLeUAb8nnvf6c7fZwCoH582XkuNJC5KtiNckNeLxSKPend2zx57b28dRu+aVZX0epL9HrkO4YAGDBOHRbpRC09PZsxLeNQPP1bDj59u/r59QUS4XGXfXT4vwTfrB+2CHnFNFW4VKaCeHxSs5h0QLQvng7ONAjlzHm2tVSZL00ao+02Cfk/HiMu3yZtkgVWNnVgTZup4peWDwfMd0LvpyaNLBKUla62UlYmp4s8t8VXg5bvkXfI6rfgqBXrqFfDYDhpCHFCmNTgb1nzzpEg3orxi+ka5s/O4WApdH37zNqsbd2QHe7Flxf0J+53B5jjKf2qG6lpcL4PPUr1hGCbnvvrrD7bD8+CsZdlUiH7B+YX5Mx0cQ9inRpSgPYnzbH/1e8bF5tZc7SzDPdIV5Yh6NXy830h3wT1X+kj3TfJ2oqK/EUxSGHcPCNqeE/d1JOStpC6ZzsiF2hGQ5SV5hSbGHBEE6Q0X8UpaK+sMza123q5oWYLsYPHXFWDJB0LJT/h44C67YmscpNPI7cV05RF+JFAUxYQArjb8XnQI0eF/Sb4hbg==

Steps to reproduce the bug

  1. Use or set up the minimal reproduction
  2. Click between the "Home" and "About" links at the top a few times. Each page has 1000 divs on it, which accumulate as detached nodes and increased memory usage with each route change.

Expected behavior

I would expect the unmounted components to be cleaned up in garbage collection, but references must still exist to the component or its elements, leading to a memory leak and degraded performance over time.

Actual behavior

The nodes are retained (can be viewed in Chrome devtool's Heap Snapshots), leading to ever-increasing detached nodes (and other objects), which leads to increased memory use over time.

Additional information

I've created a minimal setup as follows.

App.vue, which sets up the boilerplate usage for RouterView with Transition (taken from the docs), along with the related CSS transitions (some notes on this below):

<script setup lang="ts">
import { RouterView } from 'vue-router'
</script>

<template>
  <RouterView v-slot="{ Component }">
    <Transition name="fade">
      <component :is="Component" />
    </Transition>
  </RouterView>
</template>

<style>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 200ms;
}
.fade-leave-active {
  position: absolute;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>

HomeView.vue and AboutView.vue, two pages that are almost identical and that link to each other via a RouterLink, and which each generate 1,000 dummy divs to help illustrate the problem. Here is HomeView.vue:

<script setup lang="ts">
import { RouterLink } from 'vue-router';
</script>

<template>
  <div id="HOME">
    <RouterLink to="/about">About</RouterLink>
    <div
      v-for="index in 1000"
      :key="index"
    >
      Hello Home {{ index }}
    </div>
  </div>
</template>

When the Transition component is present (under certain conditions, see more info below), the component elements (and other objects in other tests I've done) are retained as detached nodes and accumulate in memory, and not disposed of through garbage collection, implying references to them exist and that the component is not properly removed after the transition (I think).

On initial load, the heap snapshot in Chrome devtools looks like this (note the "detached" filter to focus on detached nodes):

screenshot-1

Everything looks fine. After clicking the link once to switch to the next page, it looks like this (~1,000 detached nodes):

screenshot-2

After clicking the links 4 more times (so 5 total route changes with page transitions), it looks like this (~5,000 detached nodes):

screenshot-3

Note that if the Transition component is omitted this issue is no longer reproduced. When there are no more route transitions, there are still always 1,000 detached nodes (the number corresponding to a single page, which may or may not be good), but importantly the memory usage never goes up.

Notes:

  1. As I said earlier, this issue doesn't happen if there is no Transition component inside the RouterView;
  2. The Transition component alone is not enough to cause the issue: the duration matters. When no CSS matching the name is given (and so there is no visible transition) the behaviour is normal (no memory leak). When the duration is very low, it is also not an issue (I have tested with 0ms and 1ms with no issue, no memory leak). At 10ms and higher the issue is consistently reproducible. Obviously the point of using the Transition component with the RouterView is to have a transition, so I think for most use cases the duration would be much higher than these.

I hope this helps, happy to provide any other information.

@edison1105
Copy link
Member

edison1105 commented Jan 15, 2025

Similar to vuejs/core#12306
I think this is a Chrome bug. I can't reproduce it using Chrome v128, but it happens in Chrome v131.

Image

@acordy
Copy link
Author

acordy commented Jan 15, 2025

I've spent the last few hours testing this in various ways with the Nightly build of Chrome. A fix was made and merged on January 10, 2025 (discussed here).

I am no longer able to reproduce the issue in that build. So, it would seem that this was indeed a Chrome bug that will eventually make its way into the stable build.

For anyone who gets confused if they try this out themselves, I don't think they've resolved everything. As soon as you open devtools the issue can still arise, and give false positives for a memory leak. But if you reload a page with devtools closed, click around and trigger any number of route changes with a transition, and then open up devtools afterwards to check, you shouldn't see any more detached nodes (at least not due to this).

But I'd close devtools after that and ignore anything else it has to say about detached nodes until you've reloaded the page again. Hopefully this will save someone some time and sanity.

Sorry for the false alarm and thanks @edison1105 for the insight into the Chrome angle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants