Javascript a-t-il gc ?

青灯夜游
青灯夜游original
2021-10-09 16:55:332838parcourir

Il existe un GC (mécanisme de collecte des déchets) en javascript. JavaScript est un langage qui utilise un mécanisme de récupération de place. L'environnement d'exécution est responsable de la gestion de la mémoire lorsque le code est exécuté et détruit automatiquement les objets inutiles (objets non référencés) de la mémoire.

L'environnement d'exploitation de ce tutoriel : système Windows 7, JavaScript version 1.8.5, ordinateur Dell G3.

Mécanisme de collecte des déchets (GC) en JavaScript

Concepts liés à la collecte des déchets

① Qu'est-ce que les déchets

Les objets qui ne sont pas utilisés (référencés) sont des déchets.

② Qu'est-ce que le garbage collection ?

Les objets qui ne sont pas référencés sont détruits et la mémoire est libérée, ce qui est un garbage collection.

Les langages de programmation tels que C et C++ nécessitent un garbage collection manuel.

Collecte automatique des déchets pour Java, JavaScript, PHP, Python et d'autres langages.

JS dispose d'un mécanisme de collecte automatique des déchets, qui détruira automatiquement ces objets indésirables de la mémoire. Nous n'avons pas besoin et ne pouvons pas effectuer d'opérations de collecte des déchets. Tout ce que nous avons à faire est de définir les objets qui ne sont plus utilisés sur null.

Pourquoi le garbage collection est nécessaire

  • En C/C++, le suivi de l'utilisation et la gestion de la mémoire sont un gros fardeau pour les développeurs
    • JavaScript est un langage qui utilise un mécanisme de garbage collection, ce qui signifie que l'environnement d'exécution est responsable de la gestion la mémoire lorsque le code est exécuté aide les développeurs à alléger ce fardeau
    • Réaliser l'allocation de mémoire et le recyclage des ressources grâce à la gestion automatique de la mémoire
    • L'idée de base est très simple, déterminer quelle variable ne sera plus utilisée et allouer son espace mémoire Libérer
    • Ce processus est cyclique, ce qui signifie que le programme de récupération de place s'exécutera de temps en temps
  • Comme les objets, les chaînes et les objets dans JS, la mémoire n'est pas fixe, seule la mémoire réellement utilisée. La mémoire sera allouée dynamiquement lorsque le temps est écoulé
    • Ces mémoires doivent être libérées après n'avoir pas été utilisées pour être réutilisées, sinon cela provoquera un crash une fois la mémoire disponible de l'ordinateur épuisée
  • Les principales méthodes de collecte des ordures dans l'histoire du développement des navigateurs sont
    • Méthode de comptage de références
    • Méthode de marquage et d'effacement

Méthode de comptage de références

Idée

  • Les variables font simplement référence à la valeur
  • Lorsqu'une variable fait référence à la valeur, le nombre de références +1
  • Lorsque la variable Lorsque la référence est écrasée ou effacée, le nombre de références est de -1
  • Lorsque le nombre de références est de 0, cette mémoire peut être libérée en toute sécurité.
let arr = [1, 0, 1]   // [1, 0, 1]这块内存被arr引用  引用次数为1
arr = [0, 1, 0]  // [1, 0, 1]的内存引用次数为0被释放  
                 // [0, 1, 0]的内存被arr引用   引用次数为1
const tmp = arr  // [0, 1, 0]的内存被tmp引用   引用次数为2

Problème de référence circulaire

Netscape Navigator 3.0 adopte

  • Dans cet exemple, les propriétés d'ObjectA et d'ObjectB se réfèrent respectivement
  • En conséquence, une fois cette fonction exécutée, le le nombre de fois où l'objet est référencé ne deviendra pas 0, affectant le GC normal.
  • S'il est exécuté plusieurs fois, cela entraînera de graves fuites de mémoire.
  • La méthode Mark and Clear n'a pas ce problème.
function Example(){

    let ObjectA = new Object();
    let ObjectB = new Object();

    ObjectA.p = ObjectB;
    ObjectB.p = ObjectA;   

}

Example();
  • Solution : pointez-le sur null à la fin de la fonction
ObjectA = null;
ObjectB = null;

méthode mark et clear

Afin de résoudre le problème de fuite de mémoire provoqué par les références circulaires, Netscape Navigator 4.0 a commencé à utilisez la méthode mark and clear

En 2008, IE, Firefox, Opera, Chrome et Safari utilisaient tous le nettoyage de balisage (ou une variante de celui-ci) dans leurs implémentations JavaScript, ne différant que par la fréquence à laquelle ils exécutaient le garbage collection.

Idée

  • Marquez la variable "entrant" lorsqu'elle entre dans le contexte d'exécution
  • En même temps, marquez la variable "quittant" lorsqu'elle quitte le contexte d'exécution
    • Désormais, cette variable ne peut plus être accessible
    • Dans le prochain garbage collection, la mémoire est libérée en cas de besoin
function Example(n){
    const a = 1, b = 2, c = 3;
    return n * a * b * c;
}
// 标记Example进入执行上下文

const n = 1;  // 标记n进入执行上下文
Example(n);   // 标记a,b,c进入执行上下文
console.log(n); // 标记a, b, c离开执行上下文,等待垃圾回收

les instructions const et let améliorent les performances

  • const et let aident non seulement à améliorer le style de code, mais également à améliorer les performances du garbage collection
  • const et let make JS Block-level scope, lorsque la portée au niveau du bloc se termine plus tôt que la portée de la fonction, le programme de récupération de place intervient plus tôt
  • Recyclez la mémoire récupérée le plus tôt possible, améliorant ainsi les performances du garbage collection

Collecte des ordures du moteur V8

La collecte des ordures du moteur V8 adopte la méthode de marquage et de balayage et la méthode de collecte générationnelle

Il est divisé en nouvelle génération et ancienne génération

nouvelle génération

Le garbage collection de nouvelle génération utilise l'algorithme Scavenge 配 Petite mémoire et petite quantité de mémoire nouvellement allouée <code>Scavenge 算法

分配给常用内存和新分配的小量内存

  • 内存大小

    • 32位系统16M内存
    • 64位系统32M内存
  • 分区

    • 新生代内存分为以下两区,内存各占一半
    • From space
    • To space
  • 运行

    • 实际运行的只有From space
    • To space处于空闲状态
  • Scavenge

    🎜🎜🎜 taille de la mémoire 🎜🎜🎜 Système 32 bits 16 Mo de mémoire 🎜🎜 Système 64 bits 32 Mo de mémoire 🎜 🎜🎜🎜🎜 partition 🎜🎜🎜 La mémoire nouvelle génération est divisée en deux zones suivantes, chacune occupant la moitié de la mémoire🎜🎜De l'espace🎜🎜Vers l'espace🎜🎜🎜🎜🎜Exécution🎜🎜🎜Uniquement de l'espace🎜🎜Vers l'espace est actuellement en cours d'exécution et est inactif🎜🎜🎜🎜🎜Algorithme Scavenge🎜
    • 当From space内存使用将要达到上限时开始垃圾回收,将From space中的不可达对象都打上标记
    • 将From space的未标记对象复制到To space。
      • 解决了内存散落分块的问题(不连续的内存空间)
      • 相当于用空间换时间。
    • 然后清空From space、将其闲置,也就是转变为To space,俗称反转。
  • 新生代 -> 老生代

    • 新生代存放的是新分配的小量内存,如果达到以下条件中的一个,将被分配至老生代
      • 内存大小达到From space的25%
      • 经历了From space To space的一个轮回

老生代

老生代采用mark-sweep标记清除和mark-compact标记整理

通常存放较大的内存块和从新生代分配过来的内存块

  • 内存大小
    • 32位系统700M左右
    • 64位系统1.4G左右
  • 分区
    • Old Object Space
      • 字面的老生代,存放的是新生代分配过来的内存。
    • Large Object Space
      • 存放其他区域放不下的较大的内存,基本都超过1M
    • Map Space
      • 存放存储对象的映射关系
    • Code Space
      • 存储编译后的代码
  • 回收流程
    • 标记分类(三色标记)
      • 未被扫描,可回收,下面简称1类
      • 扫描中,不可回收,下面简称2类
      • 扫描完成,不可回收,下面简称3类
    • 遍历
      • 采用深度优先遍历,遍历每个对象。
      • 首先将非根部对象全部标记为1类,然后进行深度优先遍历。
      • 遍历过程中将对象压入栈,这个过程中对象被标记为2类
      • 遍历完成对象出栈,这个对象被标记为3类
      • 整个过程直至栈空
    • Mark-sweep
      • 标记完成之后,将标记为1类的对象进行内存释放

  • Mark-compact

    • 垃圾回收完成之后,内存空间是不连续的。

    • 这样容易造成无法分配较大的内存空间的问题,从而触发垃圾回收。

    • 所以,会有Mark-compact步骤将未被回收的内存块整理为连续地内存空间。

    • 频繁触发垃圾回收会影响引擎的性能,内存空间不足时也会优先触发Mark-compact

垃圾回收优化

  • 增量标记
    • 如果用集中的一段时间进行垃圾回收,新生代倒还好,老生代如果遍历较大的对象,可能会造成卡顿。
    • 增量标记:使垃圾回收程序和应用逻辑程序交替运行,思想类似Time Slicing
  • 并行回收
    • 在垃圾回收的过程中,开启若干辅助线程,提高垃圾回收效率。
  • 并发回收
    • 在逻辑程序执行的过程中,开启若干辅助线程进行垃圾回收,清理和主线程没有任何逻辑关系的内存。

内存泄露场景

全局变量

// exm1
function Example(){
    exm = &#39;LeBron&#39;   
}

// exm2
function Example(){
    this.exm = &#39;LeBron&#39;
}
Example()

未清除的定时器

const timer = setInterval(() => {
    //...
}, 1000)

// clearInterval(timer)

闭包

function debounce(fn, time) {
  let timeout = null; 
  return function () {
    if (timeout) {
      clearTimeout(timeout);
    }

    timeout = setTimeout(() => {
      fn.apply(this, arguments);
    }, time);
  };
}

const fn = debounce(handler, 1000); // fn引用了timeout

未清除的DOM元素引用

const element = {
    // 此处引用了DOM元素
    button:document.getElementById(&#39;LeBron&#39;),
    select:document.getElementById(&#39;select&#39;)
}

document.body.removeChild(document.getElementById(&#39;LeBron&#39;))

如何检测内存泄漏

这个其实不难,浏览器原带的开发者工具Performance就可以

  • 步骤
    • F12打开开发者工具
    • 选择Performance工具栏
    • 勾选屏幕截图和Memory
    • 点击开始录制
    • 一段时间之后结束录制
  • 结果
    • 堆内存会周期性地分配和释放
    • 如果堆内存的min值在逐渐上升则存在内存泄漏

优化内存使用

1、尽量不在for循环中定义函数

// exm
const fn = (idx) => {
    return idx * 2;
}

function Example(){
    for(let i=0;i<1000;i++){
        //const fn = (idx) => {
        //    return idx * 2;
        // }
        const res = fn(i);
    }
}

2、尽量不在for循环中定义对象

function Example() {
  const obj = {};
  let res = "";
  for (let i = 0; i < 1000; i++) {
    // const obj = {
    //   a: i,
    //   b: i * 2,
    //   c: i * 3,
    // };
    obj.a = i;
    obj.b = i * 2;
    obj.c = i * 3;
    res += JSON.stringify(obj);
  }
  return res
}

3、清空数组

arr = [0, 1, 2]
arr.length = 0; // 清空了数组,数组类型不变
// arr = []  // 重新申请了一块空数组对象内存

【推荐学习:javascript高级教程

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn