Home Web Front-end JS Tutorial Memory leaks in vue usage [Recommended]_vue.js

Memory leaks in vue usage [Recommended]_vue.js

Jul 12, 2018 pm 02:04 PM
vue memory leak

Memory leak refers to a new piece of memory that cannot be released or garbage collected. This article mainly introduces memory leaks in the use of vue. Friends in need can refer to

What is a memory leak? A memory leak refers to a new piece of memory that cannot be released or garbage collected. After newing an object, it allocates a piece of heap memory. When the object pointer is set to null or leaves the scope and is destroyed, then this memory will be automatically garbage collected if no one refers to it in JS. However, if the object pointer is not set to null and there is no way to obtain the object pointer in the code, the memory pointed to by it will not be released, which means a memory leak occurs. Why can’t the object pointer be obtained in the code? Here is an example:

// module date.js
let date = null;
export default {
 init () {
  date = new Date();
 }
}
// main.js
import date from 'date.js';
date.init();
Copy after login

After main.js initializes date, the date variable becomes It will exist until you close the page, because the date reference is in another module, it can be understood that the module is a closure and is invisible to the outside world. So if you want this date object to always exist and need to be used all the time, then there is no problem. But if you want to use it once and then not use it, there will be a problem. This object has been in the memory without being released, and a memory leak has occurred.

Another relatively hidden and very common memory leak is event binding, which forms a closure, causing some variables to always exist. As shown in the following example:

// 一个图片懒惰加载引擎示例
class ImageLazyLoader {
 constructor ($photoList) {
  $(window).on('scroll', () => {
   this.showImage($photoList);
  });
 }
 showImage ($photoList) {
  $photoList.each(img => {
   // 通过位置判断图片滑出来了就加载
   img.src = $(img).attr('src');
  });
 }
}
// 点击分页的时候就初始化一个图片懒惰加载的
$('.page').on('click', function () {
 new ImageLazyLoader($('img.photo'));
});
Copy after login

This is a model for lazy loading of images. Every time you click paging, the data on the previous page will be cleared and updated to The DOM of the current page and reinitializes a lazy loading engine. It listens to the scroll event and processes the DOM of the incoming picture list. Every time you click on a new page, a new page will be created. A memory leak occurs here, mainly caused by the following three lines of code:

$(window).on('scroll', () => {
 this.showImage($photoList);
});
Copy after login

Because the event binding here Defined into a closure, the two variables this/$photoList have not been released. This points to the instance of ImageLazyLoader, and $photoList points to the DOM node. When the data on the previous page is cleared, the relevant DOM node The nodes have been separated from the DOM tree, but there is still a $photoList pointing to them. As a result, these DOM nodes cannot be garbage collected and remain in the memory, and a memory leak occurs. Since this variable is also trapped by the closure and has not been released, there is also a memory leak in an instance of ImageLazyLoader.

The solution to this is relatively simple, which is to turn off the bound event when destroying the instance, as shown in the following code:

class ImageLazyLoader {
 constructor ($photoList) {
  this.scrollShow = () => {
   this.showImage($photoList);
  };
  $(window).on('scroll', this.scrollShow);
 }
 // 新增一个事件解绑       
 clear () {      
  $(window).off('scroll', this.scrollShow);
 }
 showImage ($photoList) {
  $photoList.each(img => {
   // 通过位置判断图片滑出来了就加载
   img.src = $(img).attr('src');
  });
  // 判断如果图片已全部显示,就把事件解绑了
  if (this.allShown) {
   this.clear();
  }
 }
}
// 点击分页的时候就初始化一个图片懒惰加载的
let lazyLoader = null;
$('.page').on('click', function () {
 lazyLoader && (lazyLoader.clear());
 lazyLoader = new ImageLazyLoader($('img.photo'));
});
Copy after login

Before each instantiation of an ImageLazyLoader, clear the previous instance and unbind it in clear. Since JS has a constructor but no destructor, you need to write a clear yourself and manually adjust the clear outside. At the same time, the event is automatically unbound at the appropriate time during the execution of the event. The above is to judge that if all the pictures are displayed, then there is no need to monitor the scroll event and unbind it directly. This will solve the problem of memory leaks and trigger automatic garbage collection.

Why is there no closure reference after unbinding the event? Because the JS engine detects that the closure is no longer useful, it destroys the closure, and the external variables referenced by the closure will naturally be left blank.

Okay, the basic knowledge has been explained here. Now use the memory detection tool of Chrome devtools to actually operate it to facilitate the discovery of some memory leaks on the page. In order to avoid the impact of some plug-ins installed in the browser, use Chome's incognito mode page, which will disable all plug-ins.

Then open devtools, switch to the Memory tab, and select Heap snapshot, as shown below:


What is a heap snapshot? Translated, it is a heap snapshot, taking a picture of the current memory heap. Because the dynamically applied memory is in the heap, and the local variables are in the memory stack and are allocated and managed by the operating system, there will be no memory leaks. So just be concerned about the heap situation.

Then do some operations of adding, deleting and modifying the DOM, such as:

(1) Pop up a box, and then close the box

(2) Click on a single page Jump to another route, and then click back to return

(3) Click paging to trigger dynamic DOM change

That is to first add DOM, and then delete these DOM. Take a look at these DOM changes. Whether the deleted DOM still has objects referencing them.

Here I am using the second method to detect whether there is a memory leak in a routing page of a single-page application. First open the home page, click on another page, then click back, and then click the garbage collection button:

Trigger garbage collection to avoid unnecessary interference.

Then click the photo button:

它就会把当前页面的内存堆扫描一遍显示出来,如下图所示:

然后在上面中间的Class Filter的搜索框里搜一下detached:

它就会显示所有已经分离了DOM树的DOM结点,重点关注distance值不为空的,这个distance表示距离DOM根结点的距离。上图展示的这些p具体是啥呢?我们把鼠标放上去不动等个2s,它就会显示这个p的DOM信息:

通过className等信息可以知道它就是那个要检查的页面的DOM节点,在下面的Object的窗口里面依次展开它的父结点,可以看到它最外面的父结点是一个VueComponent实例:

下面黄色字体native_bind表示有个事件指向了它,黄色表示引用仍然生效,把鼠标放到native_bind上面停留2秒:

它会提示你是在homework-web.vue这个文件有一个getScale函数绑定在了window上面,查看一下这个文件确实是有一个绑定:

mounted () {
 window.addEventListener('resize', this.getScale);
}
Copy after login

所以虽然Vue组件把DOM删除了,但是还有个引用存在,导致组件实例没有被释放,组件里面又有一个$el指向DOM,所以DOM也没有被释放。

要在beforeDestroyed里面解绑的

beforeDestroyed () {
 window.removeEventListener('resize', this.getScale);
}
Copy after login

所以综合上面的分析,造成内存泄露的可能会有以下几种情况:

(1)监听在window/body等事件没有解绑

(2)绑在EventBus的事件没有解绑

(3)Vuex的$store watch了之后没有unwatch

(4)模块形成的闭包内部变量使用完后没有置成null

(5)使用第三方库创建,没有调用正确的销毁函数

并且可以借助Chrome的内存分析工具进行快速排查,本文主要是用到了内存堆快照的基本功能,读者可以尝试分析自己的页面是否存在内存泄漏,方法是做一些操作如弹个框然后关了,拍一张堆快照,搜索detached,按distance排序,把非空的节点展开父级,找到标黄的字样说明,那些就是存在没有释放的引用。也就是说这个方法主要是分析仍然存在引用的游离DOM节点。因为页面的内存泄露通常是和DOM相关的,普通的JS变量由于有垃圾回收所以一般不会有问题,除非使用闭包把变量困住了用完了又没有置空。

DOM相关的内存泄露通常也是因为闭包和事件绑定引起的。绑了(全局)事件之后,在不需要的时候需要把它解绑。当然直接绑在p上面的可以直接把p删了,绑在它上面的事件就自然解绑了。

The above is the detailed content of Memory leaks in vue usage [Recommended]_vue.js. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1658
14
PHP Tutorial
1257
29
C# Tutorial
1231
24
How to use bootstrap in vue How to use bootstrap in vue Apr 07, 2025 pm 11:33 PM

Using Bootstrap in Vue.js is divided into five steps: Install Bootstrap. Import Bootstrap in main.js. Use the Bootstrap component directly in the template. Optional: Custom style. Optional: Use plug-ins.

How to add functions to buttons for vue How to add functions to buttons for vue Apr 08, 2025 am 08:51 AM

You can add a function to the Vue button by binding the button in the HTML template to a method. Define the method and write function logic in the Vue instance.

How to use watch in vue How to use watch in vue Apr 07, 2025 pm 11:36 PM

The watch option in Vue.js allows developers to listen for changes in specific data. When the data changes, watch triggers a callback function to perform update views or other tasks. Its configuration options include immediate, which specifies whether to execute a callback immediately, and deep, which specifies whether to recursively listen to changes to objects or arrays.

What does vue multi-page development mean? What does vue multi-page development mean? Apr 07, 2025 pm 11:57 PM

Vue multi-page development is a way to build applications using the Vue.js framework, where the application is divided into separate pages: Code Maintenance: Splitting the application into multiple pages can make the code easier to manage and maintain. Modularity: Each page can be used as a separate module for easy reuse and replacement. Simple routing: Navigation between pages can be managed through simple routing configuration. SEO Optimization: Each page has its own URL, which helps SEO.

How to return to previous page by vue How to return to previous page by vue Apr 07, 2025 pm 11:30 PM

Vue.js has four methods to return to the previous page: $router.go(-1)$router.back() uses <router-link to="/" component window.history.back(), and the method selection depends on the scene.

How to use vue traversal How to use vue traversal Apr 07, 2025 pm 11:48 PM

There are three common methods for Vue.js to traverse arrays and objects: the v-for directive is used to traverse each element and render templates; the v-bind directive can be used with v-for to dynamically set attribute values ​​for each element; and the .map method can convert array elements into new arrays.

React vs. Vue: Which Framework Does Netflix Use? React vs. Vue: Which Framework Does Netflix Use? Apr 14, 2025 am 12:19 AM

Netflixusesacustomframeworkcalled"Gibbon"builtonReact,notReactorVuedirectly.1)TeamExperience:Choosebasedonfamiliarity.2)ProjectComplexity:Vueforsimplerprojects,Reactforcomplexones.3)CustomizationNeeds:Reactoffersmoreflexibility.4)Ecosystema

How to reference js file with vue.js How to reference js file with vue.js Apr 07, 2025 pm 11:27 PM

There are three ways to refer to JS files in Vue.js: directly specify the path using the <script> tag;; dynamic import using the mounted() lifecycle hook; and importing through the Vuex state management library.

See all articles