Home >Web Front-end >Front-end Q&A >Does javascript have gc?

Does javascript have gc?

青灯夜游
青灯夜游Original
2021-10-09 16:55:332837browse

There is GC (garbage collection mechanism) in javascript. JavaScript is a language that uses a garbage collection mechanism. The execution environment is responsible for managing memory when the code is executed, and automatically destroys garbage objects (objects that are not referenced) from memory.

The operating environment of this tutorial: windows7 system, javascript version 1.8.5, Dell G3 computer.

Garbage collection mechanism (GC) in JavaScript

Garbage collection related concepts

① What is garbage

Objects that are not used (referenced) aregarbage.

② What is garbage collection

Objects that are not referenced are destroyed and the memory is released, which is garbage collection.

Programming languages ​​such as C and C require manual garbage collection.

Automatic garbage collection for Java, JavaScript, PHP, Python and other languages.

JS has an automatic garbage collection mechanism, which will automatically destroy these garbage objects from memory. We do not need and cannot perform garbage collection operations. All we need to do is set objects that are no longer used to null.

Why garbage collection is needed

  • In C/C, tracking memory usage and managing memory is a big burden for developers
    • JavaScript is A language that uses a garbage collection mechanism, which means that the execution environment is responsible for managing memory when the code is executed, helping developers to offload this burden
    • Realize memory allocation and resource recycling through automatic memory management
    • The basic idea is very simple, determine which variable will no longer be used, and release its memory space
    • This process is cyclical, which means that the garbage collection program will run every once in a while
  • The memory of objects, strings, and objects in JS is not fixed. Memory will be dynamically allocated only when it is actually used.
    • These memories need to be in Release it after not in use so that it can be used again, otherwise it will cause a crash after the computer's available memory is exhausted
  • The main garbage collection methods in the history of browser development are
    • Reference counting method
    • Mark clearing method

Reference counting method

Ideas

  • The variable only refers to the value
  • When the variable refers to the value, the number of references is 1
  • When the reference to the variable is overwritten or cleared, Number of references -1
  • When the number of references is 0, this memory can be safely released.
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

Circular reference problem

Netscape Navigator 3.0 adopts

  • In this example, the properties of ObjectA and ObjectB refer to each other respectively
  • As a result, after this function is executed, the number of times Object is referenced will not become 0, affecting normal GC.
  • If executed multiple times, it will cause serious memory leaks.
  • The mark and clear method does not have this problem.
function Example(){

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

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

}

Example();
  • Solution: Point it to null at the end of the function
ObjectA = null;
ObjectB = null;

Mark clearing method

In order to solve the memory leak problem caused by circular references, Netscape Navigator 4.0 began to use the mark and clear method

By 2008, IE, Firefox, Opera, Chrome and Safari both use markup cleaning (or a variant of it) in their JavaScript implementations, differing only in how often they run garbage collection.

Ideas

  • Mark the "entry" mark when the variable enters the execution context
  • At the same time, also when the variable leaves the execution context Mark "leave"
    • From now on, this variable cannot be accessed
    • The memory will be released during the next garbage collection
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离开执行上下文,等待垃圾回收

const and let declarations improve performance

  • const and let not only help to improve the code style, but also help improve garbage collection performance
  • const and let make JS With block-level scope, when the block-level scope ends earlier than the function scope, the garbage collection program intervenes earlier
  • Recycle the recovered memory as early as possible, improving the performance of garbage collection

Garbage collection of the V8 engine

The garbage collection of the V8 engine adopts the mark-and-sweep method and the generational collection method

Divided into new generation and old generation

New generation

##New generation garbage collection adopts

Scavenge Algorithm

Allocate to common memory and newly allocated small amount of memory

  • Memory size

      32-bit system 16M memory
    • 64-bit system 32M memory
  • ##Partition
  • The new generation memory is divided into the following two Area, half of the memory
    • From space
    • To space
  • Run
  • actually run Only From space
    • To space is idle
  • ##Scavenge
  • Algorithm

    • 当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 = 'LeBron'   
}

// exm2
function Example(){
    this.exm = 'LeBron'
}
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('LeBron'),
    select:document.getElementById('select')
}

document.body.removeChild(document.getElementById('LeBron'))

如何检测内存泄漏

这个其实不难,浏览器原带的开发者工具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高级教程

The above is the detailed content of Does javascript have gc?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
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