memory leak

Memory leak: How to avoid it in Vue js

What is memory leak?

In computer science, a memory leak is a type of resource leak. It occurs when a computer program incorrectly manages memory allocations in a way that memory which is no longer needed is not released. A memory leak may also happen when an object is stored in memory but cannot be accessed by the running code. A memory leak has symptoms similar to a number of other problems. And it generally can only be diagnosed by a programmer with access to the programs’ source code.

A space leak occurs when a computer program uses more memory than necessary. In contrast to memory leaks, the memory consumed by a space leak is released, but later than expected.

If you are developing applications with Vue, you need to watch out for memory leaks. This issue is especially important in Single Page Applications (SPAs). Because of the design, users should not have to refresh their browser when using an SPA. So it is up to the JavaScript application to clean up components. And make sure that garbage collection takes place as expected.

Memory leaks in Vue applications do not typically come from Vue itself, rather they can happen when incorporating other libraries into an application.

Also Read:

Reactivity in VueJS: Useful understanding you need to know

Vue JS vs React JS: Which is good choice for UI development

Simple Example of Memory Leak

The following example shows a memory leak caused by using the Choices.js library in a Vue component and not properly cleaning it up. Later, we will show how to remove the Choices.js footprint and avoid the memory leak.

In the example below, we load up a select with a lot of options. Then we use a show/hide button with a v-if directive to add it and remove it from the virtual DOM. The problem with this example is that the v-if directive removes the parent element from the DOM, but we did not clean up the additional DOM pieces created by Choices.js, causing a memory leak.

<link rel='stylesheet prefetch' href='https://joshuajohnson.co.uk/Choices/assets/styles/css/choices.min.css?version=3.0.3'>
<script src='https://joshuajohnson.co.uk/Choices/assets/scripts/dist/choices.min.js?version=3.0.3'></script>

<div id="app">
  <button
    v-if="showChoices"
    @click="hide"
  >Hide</button>
  <button
    v-if="!showChoices"
    @click="show"
  >Show</button>
  <div v-if="showChoices">
    <select id="choices-single-default"></select>
  </div>
</div>
new Vue({
  el: "#app",
  data: function () {
    return {
      showChoices: true
    }
  },
  mounted: function () {
    this.initializeChoices()
  },
  methods: {
    initializeChoices: function () {
      let list = []
      // lets load up our select with many choices
      // so it will use a lot of memory
      for (let i = 0; i < 1000; i++) {
        list.push({
          label: "Item " + i,
          value: i
        })
      }
      new Choices("#choices-single-default", {
        searchEnabled: true,
        removeItemButton: true,
        choices: list
      })
    },
    show: function () {
      this.showChoices = true
      this.$nextTick(() => {
        this.initializeChoices()
      })
    },
    hide: function () {
      this.showChoices = false
    }
  }
})

To see this memory leak in action, open this CodePen example using Chrome and then open the Chrome Task Manager. To open the Chrome Task Manager on Mac, choose Chrome Top Navigation > Window > Task Manager or on Windows, use the Shift+Esc shortcut. Now, click the show/hide button 50 or so times. You should see the memory usage in the Chrome Task Manager increase and never be reclaimed.

Memory Leak Example

Resolving the Memory Leak

In the above example, we can use our hide() method to do some clean up and solve the memory leak prior to removing the select from the DOM. To accomplish this, we will keep a property in our Vue instance’s data object and we will use the Choices API’s destroy() method to perform the clean up.

Check the memory usage again with this updated CodePen example.

new Vue({
  el: "#app",
  data: function () {
    return {
      showChoices: true,
      choicesSelect: null
    }
  },
  mounted: function () {
    this.initializeChoices()
  },
  methods: {
    initializeChoices: function () {
      let list = []
      for (let i = 0; i < 1000; i++) {
        list.push({
          label: "Item " + i,
          value: i
        })
      }
      // Set a reference to our choicesSelect in our Vue instance's data object
      this.choicesSelect = new Choices("#choices-single-default", {
        searchEnabled: true,
        removeItemButton: true,
        choices: list
      })
    },
    show: function () {
      this.showChoices = true
      this.$nextTick(() => {
        this.initializeChoices()
      })
    },
    hide: function () {
      // now we can use the reference to Choices to perform clean up here
      // prior to removing the elements from the DOM
      this.choicesSelect.destroy()
      this.showChoices = false
    }
  }
})

Details about the Value

Memory management and performance testing can easily be neglected in the excitement of shipping quickly. However, keeping a small memory footprint is still important to your overall user experience.

Consider the types of devices your users may be using and what their normal flow will be. Could they use memory constrained laptops or mobile devices? Do your users typically do lots of in-application navigation? If either of these are true, good memory management practices can help you avoid the worst case scenario of crashing a user’s browser. Even if neither of these are true, you can still potentially have degradation of performance over extended usage of your app if you are not careful.

Real-World Example

In the above example, we used a v-if directive to illustrate the memory leak, but a more common real-world scenario happens when using vue-router to route to components in a Single Page Application.

Just like the v-if directive, vue-router removes elements from the virtual DOM and replaces those with new elements when a user navigates around your application. The Vue beforeDestroy() lifecycle hook is a good place to solve the same sort of issue in a vue-router based application.

We could move our clean up into the beforeDestroy() hook like this:

beforeDestroy: function () {
    this.choicesSelect.destroy()
}

Alternative Patterns

We have discussed managing memory when removing elements. But what if you intentionally want to preserve state and keep elements in memory? In this case, you can use the built-in component keep-alive.

When you wrap a component with keep-alive, its state will be preserved and therefore kept in memory.

<button @click="show = false">Hide</button>
<keep-alive>
  <!-- my-component will be intentionally kept in memory even when removed -->
  <my-component v-if="show"></my-component>
</keep-alive>

This technique can be useful to improve user experience. For example, imagine a user starts entering comments into a text input and then decides to navigate away. If the user then navigated back, their comments would still be preserved.

Once you use keep-alive, then you have access to two more lifecycle hooks: activated and deactivated. If you do want to clean up or change data when a keep-alive component is removed, you can do so in the deactivated hook.

deactivated: function () {
  // remove any data you do not want to keep alive
}

Wrapping Up

Vue makes it very easy to develop amazing, reactive JavaScript applications. But you still need to be careful about memory leaks. These leaks will often occur when using additional 3rd Party libraries that manipulate the DOM outside of Vue. Make sure to test your application for memory leaks and take appropriate steps to clean up components where necessary.

Want to work with web development company?

A development company is the best option if you’re planning a mid-sized or large project but don’t have your own team. To clarify, the biggest advantage of a software development company is that they can take ownership of the whole project.

If you’re considering web development services, you can explore more about us – ArrowHiTech. We are proud to be one of the most well-established outsourcing companies all around the world. In addition, with over 12 years of experience, we can provide the best software development services for your eCommerce business.

So, you can check us out now: ArrowHiTech services. Also, if you want to go through our showcase, you should visit our product page here: MageSolution or our portfolio: ArrowHiTech portfolio.

ArrowHiTech services

If you have any questions, don’t hesitate to contact us via:

  • Email: support@arrowhitech.com
  • Phone number: +84 243 7955 813.