Heim Web-Frontend js-Tutorial Speicherlecks bei der Vue-Nutzung [Empfohlen]_vue.js

Speicherlecks bei der Vue-Nutzung [Empfohlen]_vue.js

Jul 12, 2018 pm 02:04 PM
vue 内存泄漏

Speicherleck bedeutet, dass kein neues Stück Speicher freigegeben oder Garbage Collection durchgeführt werden kann. In diesem Artikel werden hauptsächlich Speicherlecks bei der Verwendung von Vue vorgestellt. Freunde in Not können sich darauf beziehen

Was ist ein Speicherleck? Ein Speicherverlust bezieht sich auf einen neuen Teil des Speichers, der nicht freigegeben oder durch Müll gesammelt werden kann. Nach der Neuerstellung eines Objekts wird ein Teil des Heap-Speichers zugewiesen. Wenn der Objektzeiger auf Null gesetzt wird oder den Gültigkeitsbereich verlässt und zerstört wird, wird dieser Speicher automatisch in JS gespeichert, wenn niemand darauf verweist. Wenn der Objektzeiger jedoch nicht auf Null gesetzt ist und es keine Möglichkeit gibt, den Objektzeiger im Code abzurufen, wird der Speicher, auf den er zeigt, nicht freigegeben, was bedeutet, dass ein Speicherverlust auftritt. Warum kann dieser Objektzeiger nicht im Code abgerufen werden? Hier ist ein Beispiel:

// module date.js
let date = null;
export default {
 init () {
  date = new Date();
 }
}
// main.js
import date from 'date.js';
date.init();
Nach dem Login kopieren

Nachdem main.js das Datum initialisiert hat, wird die Datumsvariable zu „Es wird“. bestehen, bis Sie die Seite schließen. Da sich die Datumsreferenz in einem anderen Modul befindet, kann davon ausgegangen werden, dass das Modul ein Abschluss ist und für die Außenwelt unsichtbar ist. Wenn Sie also möchten, dass dieses Datumsobjekt immer vorhanden ist und ständig verwendet werden muss, gibt es kein Problem. Wenn Sie es jedoch einmal verwenden und dann nicht verwenden möchten, liegt ein Problem vor Der Speicher wurde nicht freigegeben, und es ist ein Speicherleck aufgetreten.

Ein weiterer subtilerer und häufiger auftretender Speicherverlust ist die Ereignisbindung, die einen Abschluss bildet und dazu führt, dass einige Variablen immer vorhanden sind. Wie im folgenden Beispiel gezeigt:

// 一个图片懒惰加载引擎示例
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'));
});
Nach dem Login kopieren

Dies ist ein Modell für das verzögerte Laden von Bildern. Jedes Mal, wenn Sie auf die Seite klicken, werden die Daten auf der vorherigen Seite angezeigt wird gelöscht und auf das DOM der aktuellen Seite aktualisiert und initialisiert eine Lazy-Loading-Engine neu. Es lauscht auf das Scroll-Ereignis und verarbeitet das DOM der eingehenden Bildliste. Jedes Mal, wenn Sie auf eine neue Seite klicken, wird hier ein Speicherverlust erstellt, der hauptsächlich durch die folgenden drei Codezeilen verursacht wird:

$(window).on('scroll', () => {
 this.showImage($photoList);
});
Nach dem Login kopieren

Da die Ereignisbindung hier in einem Abschluss definiert ist, wurden die beiden Variablen this/$photoList nicht freigegeben. Dies zeigt auf die Instanz von ImageLazyLoader und $photoList zeigt auf den DOM-Knoten relevanter DOM-Knoten Die Knoten wurden vom DOM-Baum getrennt, aber es gibt immer noch eine $photoList, die auf sie verweist. Daher können diese DOM-Knoten nicht durch Müll gesammelt werden und verbleiben im Speicher, und es kommt zu einem Speicherverlust. Da diese Variable ebenfalls durch den Abschluss abgefangen wird und nicht freigegeben wurde, liegt auch ein Speicherverlust in einer Instanz von ImageLazyLoader vor.

Die Lösung hierfür ist relativ einfach, nämlich das Deaktivieren des gebundenen Ereignisses beim Zerstören der Instanz, wie im folgenden Code gezeigt:

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'));
});
Nach dem Login kopieren

Löschen Sie vor jeder Instanziierung eines ImageLazyLoaders die vorherige Instanz und lösen Sie die Bindung im Clear. Da JS einen Konstruktor, aber keinen Destruktor hat, müssen Sie selbst einen Clear schreiben und den Clear außerhalb manuell anpassen. Gleichzeitig wird die Bindung des Ereignisses zum entsprechenden Zeitpunkt während der Ausführung des Ereignisses automatisch aufgehoben. Das Obige dient dazu, zu beurteilen, ob das Bildlaufereignis nicht überwacht und die Bindung direkt aufgehoben werden muss. Dadurch wird das Problem von Speicherlecks gelöst und eine automatische Speicherbereinigung ausgelöst.

Warum gibt es nach der Entbindung der Veranstaltung keinen Abschlusshinweis? Da die JS-Engine erkennt, dass der Abschluss nicht mehr nützlich ist, zerstört sie den Abschluss und die externen Variablen, auf die der Abschluss verweist, bleiben natürlich leer.

Okay, die Grundkenntnisse wurden hier erklärt. Verwenden Sie nun das Speichererkennungstool von Chrome Devtools, um es erneut zu betreiben und die Erkennung einiger Speicherlecks auf der Seite zu erleichtern. Um die Auswirkungen einiger im Browser installierter Plug-Ins zu vermeiden, verwenden Sie die Inkognito-Modus-Seite von Chome, die alle Plug-Ins deaktiviert.

Öffnen Sie dann Devtools, wechseln Sie zur Registerkarte „Speicher“ und wählen Sie Heap-Snapshot aus, wie unten gezeigt:


Was ist ein Heap-Snapshot? Übersetzt handelt es sich um einen Heap-Snapshot, der ein Bild des aktuellen Speicher-Heaps erstellt. Da sich der dynamisch angewendete Speicher im Heap befindet und die lokalen Variablen im Speicherstapel liegen und vom Betriebssystem zugewiesen und verwaltet werden, kommt es zu keinen Speicherverlusten. Seien Sie also einfach besorgt über die Heap-Situation.

Führen Sie dann einige Vorgänge zum Hinzufügen, Löschen und Ändern des DOM aus, wie zum Beispiel:

(1) Öffnen Sie ein Feld und schließen Sie dann das Popup

(2 ) Klicken Sie auf eine einzelne Seite. Springen Sie zu einer anderen Route und klicken Sie dann auf „Zurück“, um zurückzukehren

(3) Klicken Sie auf „Paging“, um eine dynamische Änderung des DOM auszulösen

Das heißt, zuerst DOM hinzuzufügen und dann zu löschen Schauen Sie sich diese DOM an. Sehen Sie sich an, ob das gelöschte DOM noch Objekte enthält, die auf sie verweisen.

Hier verwende ich die zweite Methode, um zu erkennen, ob in einer Routing-Seite einer Single-Page-Anwendung ein Speicherverlust vorliegt. Öffnen Sie zuerst die Startseite, klicken Sie auf eine andere Seite, klicken Sie dann auf „Zurück“ und dann auf die Schaltfläche „Garbage Collection“:

, um die Garbage Collection auszulösen und unnötige Störungen zu vermeiden.

Dann klicken Sie auf den Foto-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);
}
Nach dem Login kopieren

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

要在beforeDestroyed里面解绑的

beforeDestroyed () {
 window.removeEventListener('resize', this.getScale);
}
Nach dem Login kopieren

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

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

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

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

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

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

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

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

Das obige ist der detaillierte Inhalt vonSpeicherlecks bei der Vue-Nutzung [Empfohlen]_vue.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

Video Face Swap

Video Face Swap

Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

So verwenden Sie Bootstrap in Vue So verwenden Sie Bootstrap in Vue Apr 07, 2025 pm 11:33 PM

Die Verwendung von Bootstrap in Vue.js ist in fünf Schritte unterteilt: Startstrap installieren. Bootstrap in main.js. Verwenden Sie die Bootstrap -Komponente direkt in der Vorlage. Optional: benutzerdefinierter Stil. Optional: Verwenden Sie Plug-Ins.

So fügen Sie Funktionen zu Schaltflächen für Vue hinzu So fügen Sie Funktionen zu Schaltflächen für Vue hinzu Apr 08, 2025 am 08:51 AM

Sie können der VUE -Taste eine Funktion hinzufügen, indem Sie die Taste in der HTML -Vorlage an eine Methode binden. Definieren Sie die Methode und schreiben Sie die Funktionslogik in der VUE -Instanz.

So verwenden Sie Watch in Vue So verwenden Sie Watch in Vue Apr 07, 2025 pm 11:36 PM

Mit der Watch -Option in Vue.js können Entwickler auf Änderungen in bestimmten Daten anhören. Wenn sich die Daten ändert, löst sich eine Rückruffunktion aus, um Aktualisierungsansichten oder andere Aufgaben auszuführen. Zu den Konfigurationsoptionen gehören unmittelbar, die festlegen, ob ein Rückruf sofort ausgeführt werden soll, und Deep, das feststellt, ob Änderungen an Objekten oder Arrays rekursiv anhören sollen.

Was bedeutet VUE Multi-Page-Entwicklung? Was bedeutet VUE Multi-Page-Entwicklung? Apr 07, 2025 pm 11:57 PM

VUE Multi-Page-Entwicklung ist eine Möglichkeit, Anwendungen mithilfe des Vue.js-Frameworks zu erstellen, in dem die Anwendung in separate Seiten unterteilt ist: Code-Wartung: Die Aufteilung der Anwendung in mehrere Seiten kann das Verwalten und Wartungsbereich erleichtern. Modularität: Jede Seite kann als separates Modul für eine einfache Wiederverwendung und den Austausch verwendet werden. Einfaches Routing: Die Navigation zwischen Seiten kann durch einfache Routing -Konfiguration verwaltet werden. SEO -Optimierung: Jede Seite hat eine eigene URL, die SEO hilft.

So verweisen Sie auf die JS -Datei mit Vue.js So verweisen Sie auf die JS -Datei mit Vue.js Apr 07, 2025 pm 11:27 PM

Es gibt drei Möglichkeiten, sich auf JS -Dateien in Vue.js zu beziehen: Geben Sie den Pfad direkt mit dem & lt; Skript & gt an. Etikett;; Dynamischer Import mit dem montierten () Lebenszyklushaken; und importieren über die Vuex State Management Library.

So kehren Sie von Vue zur vorherigen Seite zurück So kehren Sie von Vue zur vorherigen Seite zurück Apr 07, 2025 pm 11:30 PM

VUE.JS hat vier Methoden, um zur vorherigen Seite zurückzukehren: $ router.go (-1) $ router.back () verwendet & lt; Router-Link to = & quot;/& quot; Komponentenfenster.history.back () und die Methodenauswahl hängt von der Szene ab.

So verwenden Sie Vue Traversal So verwenden Sie Vue Traversal Apr 07, 2025 pm 11:48 PM

Es gibt drei gängige Methoden für Vue.js, um Arrays und Objekte zu durchqueren: Die V-für-Anweisung wird verwendet, um jedes Element zu durchqueren und Vorlagen zu rendern; Die V-Bind-Anweisung kann mit V-für dynamisch Attributwerte für jedes Element verwendet werden. und die .MAP -Methode kann Array -Elemente in Neuarrays umwandeln.

Wie man zum Div von Vue springt Wie man zum Div von Vue springt Apr 08, 2025 am 09:18 AM

Es gibt zwei Möglichkeiten, Divelemente in Vue zu springen: Verwenden Sie Vue Router und fügen Sie Router-Link-Komponente hinzu. Fügen Sie den @click Event -Listener hinzu und nennen Sie dies. $ Router.push () Methode zum Springen.

See all articles