vue: Memory leak with component with input with v-model

Version

2.6.10

Reproduction

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <script src="https://unpkg.com/vue"></script>

    <div id="app">
      <div id="nav">
        <button @click="goHome">go to Home</button>
        <button @click="goAbout">go to About</button>
      </div>
      <component :is="current"></component>
    </div>

    <script>
      const Home = {
        name: 'Home',
        template: `
      <div>
        <h2>Home</h2>
      </div>
      `,
      }

      const About = {
        template: `
        <div class="about">
    <h1>This is an about page</h1>
    <input type="text" v-model="input">
  </div>
      `,
        name: 'about',
        data: () => ({
          input: '',
        }),
      }

      const vm = new Vue({
        el: '#app',
        data() {
          return {
            current: 'Home',
          }
        },

        methods: {
          goHome() {
            this.current = 'Home'
          },
          goAbout() {
            this.current = 'About'
          },
        },
        components: { Home, About },
      })
    </script>
  </body>
</html>

Screen Shot 2019-05-09 at 18 59 07

Steps to reproduce

  • go to the about page
  • type in the input
  • leave the page
  • collect garbage and take a snapshot with devtools

What is expected?

VueComponent count should be stable

What is actually happening?

VueComponent count keeps increasing.


seems to be related to typing in the input

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 14
  • Comments: 20 (3 by maintainers)

Most upvoted comments

@posva, i just found out PR #10085 can fix it, my Chrome Version is 74.0.3729.169.

I also tried this solution, but only half of it worked. chrome80/vue2.6.11/vue-router 3.0. While vue component has been successfully recycled, three additional listeners have not been removed and dom cannot be recycled. Looking at the heap snapshot,the VueComponent increment is 0, but htmlInputElement has not been recycled, as Performance tools proves. I tracked that these 3 listeners comes from “vue/src/platforms/web/runtime/directs/model.js”–>function onCompositionStart and onCompositionEnd, But I’m not familiar with vue source code . when input element is deep in a large component, this leads to a large memory leak.

I can confirm that PR #10085 fixes it for us as well. Is there a plan to merge this?

So… any workarounds so far? Downgrade to v2.6.9?

Thanks for using Chrome! And sorry for bothering you… m(_ _)m

Chrome Canary 93.0.4535.2 (at leas) clears undo stack for removed , <textarea> content editable. So, undo stack is no more source of memory leak. (http://crbug.com/961494)

I attempt to take memory snapshot for posva’s sample. Retainers of “Detached HTMLInputElemnt” are:

  1. ShadowRoot
  2. Detached HTMLInputElement
  3. Detached HTMLDivElement
  4. Detached Text
  5. elm in VNode from vue:767
  6. Blink roots
  7. Blink roots

Note: You can make ShadowRoot to detached by <input>.value = '' (remove Text node) and <input>.type ='hidden' (remove ShadowRoot)

I’m not sure Blink roots of 6 and 7. One of Blink roots may be caused by <input>.focus().

Anyway, Detached HTMLInputElement is only one, so memory issue is mitigated.

@posva can you please update us on the status of this fix? As still happens in PROD.

it isn’t in 74. It could be a bug on Chrome. I’ve found leaks in the past (https://bugs.chromium.org/p/chromium/issues/detail?id=949587). I didn’t test with this one though as it looks like Vue is retaining the component and the browser cannot free it

@posva After further testing. This might not be Vue’s fault.

Testing the code above on Chrome Version 72.0.3626.121 (mac) seems to run without any issues and VueComponent count is stable.