Recommandations associées : "Tutoriel vidéo javascript"
La plupart du temps, nous développons uniquement sans comprendre les connaissances en matière de gestion de la mémoire. Le moteur JS s’en chargera pour nous. Cependant, nous rencontrons parfois des problèmes tels que des fuites de mémoire. Ce n'est qu'en connaissant le fonctionnement de l'allocation de mémoire que nous pouvons résoudre ces problèmes.
Dans cet article, nous présentons principalement les principes de fonctionnement de l'allocation de mémoire et du garbage collection et comment éviter certains problèmes courants de fuites de mémoire.
Cycle de vie du cache (mémoire)
Dans JS, lorsque nous créons une variable, une fonction ou tout autre objet, le moteur JS lui alloue de la mémoire et la libère lorsqu'elle n'est plus nécessaire.
Allocation de mémoire est le processus de réservation d'espace en mémoire, tandis que Libérer de la mémoire libère de l'espace pour le préparer à d'autres fins.
Chaque fois que nous allouons une variable ou créons une fonction, le stockage de cette variable passe par les mêmes étapes :
Allouer de la mémoire
- JS gère cela pour nous : il alloue la mémoire dont nous avons besoin pour créer l'objet.
Utiliser la mémoire
- L'utilisation de la mémoire est quelque chose que nous faisons explicitement dans le code : la lecture et l'écriture de la mémoire sont en fait l'utilisation de variables Read et. écrire.
Libérer la mémoire
- Cette étape est également gérée par le moteur JS, une fois la mémoire allouée libérée, elle peut être utilisée à de nouvelles fins .
« Objet » dans le contexte de la gestion de la mémoire inclut non seulement les objets JS, mais également les fonctions et les étendues de fonctions.
Memory Heap and Stack
Nous savons désormais que pour tout ce que nous définissons dans JS, le moteur alloue de la mémoire et la libère lorsqu'elle n'est plus nécessaire.
La prochaine question qui me vient à l’esprit est : où ces choses seront-elles stockées ?
Le moteur JS peut stocker des données à deux endroits : tas de mémoire et pile. Le tas et la pile sont deux structures de données utilisées par le moteur à des fins différentes.
Pile : allocation de mémoire statique
La pile est une structure de données utilisée par JS pour stocker des données statiques. Les données statiques sont des données dont le moteur connaît la taille au moment de la compilation. En JS, cela inclut les valeurs primitives (strings
, number
, boolean
, undefined
et null
) et les types de référence qui pointent vers des objets et des fonctions.
Puisque le moteur sait que la taille ne changera pas, il allouera une quantité fixe de mémoire pour chaque valeur.
Le processus d'allocation de mémoire immédiatement avant l'exécution est appelé allocation de mémoire statique. Les limites de ces valeurs et de l'ensemble de la pile dépendent du navigateur.
Heap : Allocation dynamique de mémoire
Heap est un autre espace où les données sont stockées, où JS stocke les objets et les fonctions .
Contrairement à la pile, le moteur JS n'alloue pas une quantité fixe de mémoire pour ces objets, mais alloue de l'espace selon les besoins. Cette façon d'allouer de la mémoire est également appelée allocation dynamique de mémoire.
Les caractéristiques de ces deux magasins seront comparées ci-dessous :
堆栈 | 堆 |
---|---|
存放基本类型和引用 大小在编译时已知 分配固定数量的内存 |
对象和函数 在运行时才知道大小 没怎么限制 |
Exemples
Prenons quelques exemples pour valoriser l’image.
const person = { name: 'John', age: 24, };
JS alloue de la mémoire pour cet objet dans le tas. Les valeurs réelles sont toujours les valeurs d'origine, c'est pourquoi elles sont stockées sur la pile.
const hobbies = ['hiking', 'reading'];
Les tableaux sont aussi des objets, c'est pourquoi ils sont stockés dans le tas.
let name = 'John'; // 为字符串分配内存 const age = 24; // 为字分配内存 name = 'John Doe'; // 为新字符串分配内存 const firstName = name.slice(0,4); // 为新字符串分配内存
La valeur d'origine est immuable, donc JS ne modifie pas la valeur d'origine, mais en crée une nouvelle.
Références en JavaScript
Toutes les variables pointent d'abord vers la pile. S'il s'agit d'une valeur non primitive, 堆栈
contient une référence à l'objet dans 堆
.
La mémoire du tas n'est pas triée de manière spécifique, nous devons donc en conserver une référence sur la pile. Nous pouvons considérer 引用
comme des adresses, et les objets dans le tas comme les maisons auxquelles appartiennent ces adresses.
Rappelez-vous que JS stocke les objets et les fonctions sur le tas. Les types primitifs et les références sont stockés sur la pile.
Sur cette photo, nous pouvons observer comment différentes valeurs sont stockées. Remarquez comment person
et newPerson
pointent vers le même objet.
Exemple
const person = { name: 'John', age: 24, };
Cela créera un nouvel objet dans le tas et une référence à l'objet sur la pile.
Garbage Collection
Maintenant, nous savons comment JS alloue de la mémoire pour divers objets, mais dans le cycle de vie de la mémoire, il y a une dernière étape : Libérer la mémoire.
Tout comme l'allocation de mémoire, le moteur JavaScript gère également cette étape pour nous. Plus précisément, le Garbage Collector en est responsable.
Une fois que le moteur JS reconnaît qu'une variable ou une fonction n'est plus nécessaire, il libère la mémoire qu'elle occupait.
Le principal problème est qu'il est indécis de savoir si de la mémoire est encore nécessaire, ce qui signifie qu'il est impossible d'avoir un algorithme capable de collecter immédiatement toute la mémoire qui n'est plus nécessaire au moment où elle l'est. n'est plus nécessaire.
Certains algorithmes peuvent très bien résoudre ce problème. J'aborderai les méthodes les plus couramment utilisées dans cette section : les algorithmes 引用计数
et 标记清除
.
Nombre de références
Lorsqu'une variable est déclarée et qu'une valeur de type référence est attribuée à la variable, le nombre de références à cette valeur est 1
. Si la même valeur est attribuée à une autre variable, le nombre de références à la valeur est augmenté de 1
. A l'inverse, si la variable contenant une référence à cette valeur obtient une autre valeur, le nombre de références à cette valeur est réduit de 1
.
Lorsque le nombre de références à cette valeur devient 0
, cela signifie qu'il n'y a plus moyen d'accéder à cette valeur, donc l'espace mémoire qu'elle occupe peut être récupéré. De cette façon, la prochaine fois que le garbage collector s'exécutera, il libérera la mémoire occupée par les valeurs sans références.
Regardons l'exemple ci-dessous.
Veuillez noter que dans la dernière image, seul hobbies
est laissé dans le tas, car la dernière référence est l'objet.
Nombre de cycles
引用计数
Le problème avec l'algorithme est qu'il ne prend pas en compte les références circulaires. Cela se produit lorsqu'un ou plusieurs objets se réfèrent les uns aux autres mais qu'ils ne sont plus accessibles via le code.
let son = { name: 'John', }; let dad = { name: 'Johnson', } son.dad = dad; dad.son = son; son = null; dad = null;
Puisque les objets parents font référence les uns aux autres, l'algorithme ne libère pas la mémoire allouée et on ne peut plus accéder aux deux objets.
Les définir sur null
ne fera pas reconnaître par l'algorithme de comptage de références qu'elles ne sont plus utilisées, car elles ont toutes des références entrantes.
Marquer et balayer
L'algorithme de marquage et de balayage propose des solutions pour les dépendances cycliques. Il détecte s'ils sont accessibles depuis root
objets au lieu de simplement calculer la référence à l'objet donné.
Le root
du navigateur est un objet window
, tandis que le root
dans NodeJS est un global
.
L'algorithme marque les objets inaccessibles comme des déchets, puis les analyse (les collecte). L'objet racine ne sera jamais collecté.
De cette façon, les dépendances circulaires ne sont plus un problème. Dans l'exemple précédent, ni l'objet dad
ni l'objet son
ne sont accessibles depuis la racine. Ils seront donc tous marqués comme déchets et collectés.
Cet algorithme est implémenté dans tous les navigateurs modernes depuis 2012. Seules les performances et la mise en œuvre ont été améliorées, mais l'idée centrale de l'algorithme reste la même.
Marques déposées
Le garbage collection automatique nous permet de nous concentrer sur la création d'applications au lieu de perdre du temps sur la gestion de la mémoire. Cependant, il existe des compromis.
Utilisation de la mémoire
Étant donné que l'algorithme ne sait pas exactement quand la mémoire n'est plus nécessaire, une application JS peut utiliser plus de mémoire qu'elle n'en a réellement besoin.
Même si un objet est marqué comme poubelle, c'est au garbage collector de décider quand et si la mémoire allouée sera collectée.
如果你希望应用程序尽可能提高内存效率,那么最好使用低级语言。 但是请记住,这需要权衡取舍。
性能
收集垃圾的算法通常会定期运行以清理未使用的对象。
问题是我们开发人员不知道何时会回收。 收集大量垃圾或频繁收集垃圾可能会影响性能。然而,用户或开发人员通常不会注意到这种影响。
内存泄漏
在全局变量中存储数据,最常见内存问题可能是内存泄漏。
在浏览器的 JS 中,如果省略var
,const
或let
,则变量会被加到window
对象中。
users = getUsers();
在严格模式下可以避免这种情况。
除了意外地将变量添加到根目录之外,在许多情况下,我们需要这样来使用全局变量,但是一旦不需要时,要记得手动的把它释放了。
释放它很简单,把 null
给它就行了。
window.users = null;
被遗忘的计时器和回调
忘记计时器和回调可以使我们的应用程序的内存使用量增加。 特别是在单页应用程序(SPA)中,在动态添加事件侦听器和回调时必须小心。
被遗忘的计时器
const object = {}; const intervalId = setInterval(function() { // 这里使用的所有东西都无法收集直到清除`setInterval` doSomething(object); }, 2000);
上面的代码每2秒运行一次该函数。 如果我们的项目中有这样的代码,很有可能不需要一直运行它。
只要setInterval
没有被取消,则其中的引用对象就不会被垃圾回收。
确保在不再需要时清除它。
clearInterval(intervalId);
被遗忘的回调
假设我们向按钮添加了onclick
侦听器,之后该按钮将被删除。旧的浏览器无法收集侦听器,但是如今,这不再是问题。
不过,当我们不再需要事件侦听器时,删除它们仍然是一个好的做法。
const element = document.getElementById('button'); const onClick = () => alert('hi'); element.addEventListener('click', onClick); element.removeEventListener('click', onClick); element.parentNode.removeChild(element);
脱离DOM引用
内存泄漏与前面的内存泄漏类似:它发生在用 JS 存储DOM
元素时。
const elements = []; const element = document.getElementById('button'); elements.push(element); function removeAllElements() { elements.forEach((item) => { document.body.removeChild(document.getElementById(item.id)) }); }
删除这些元素时,我们还需要确保也从数组中删除该元素。否则,将无法收集这些DOM元素。
const elements = []; const element = document.getElementById('button'); elements.push(element); function removeAllElements() { elements.forEach((item, index) => { document.body.removeChild(document.getElementById(item.id)); elements.splice(index, 1); }); }
由于每个DOM元素也保留对其父节点的引用,因此可以防止垃圾收集器收集元素的父元素和子元素。
总结
在本文中,我们总结了 JS 中内存管理的核心概念。写这篇文章可以帮助我们理清一些我们不完全理解的概念。
希望这篇对你有所帮助,我们下期再见,记得三连哦!
原文地址:https://felixgerschau.com/javascript-memory-management/
作者:Ahmad shaded
译文地址:https://segmentfault.com/a/1190000037651993
更多编程相关知识,请访问:编程入门!!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。


Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

PhpStorm version Mac
Le dernier (2018.2.1) outil de développement intégré PHP professionnel

Télécharger la version Mac de l'éditeur Atom
L'éditeur open source le plus populaire

mPDF
mPDF est une bibliothèque PHP qui peut générer des fichiers PDF à partir de HTML encodé en UTF-8. L'auteur original, Ian Back, a écrit mPDF pour générer des fichiers PDF « à la volée » depuis son site Web et gérer différentes langues. Il est plus lent et produit des fichiers plus volumineux lors de l'utilisation de polices Unicode que les scripts originaux comme HTML2FPDF, mais prend en charge les styles CSS, etc. et présente de nombreuses améliorations. Prend en charge presque toutes les langues, y compris RTL (arabe et hébreu) et CJK (chinois, japonais et coréen). Prend en charge les éléments imbriqués au niveau du bloc (tels que P, DIV),

Dreamweaver Mac
Outils de développement Web visuel