Record--JS Garbage Collection Mechanism

Here I will share with you some of the knowledge I have summarized on the Internet, I hope it will be helpful to everyone

foreword

Garbage Collection (Garbage Collection) is a memory management mechanism that is used to detect and clean up memory that is no longer used by the program. These memory that are no longer used are called garbage. The garbage collector will run periodically inside the JS engine (browser or nodejs), and generally does not require manual operation by developers.

However, understanding the working principle of the garbage collection mechanism helps us write more efficient JS code, so that the JS engine can better help us complete garbage collection, and avoid memory leaks in the applications we develop.

How is garbage produced?

Data types in JS include primitive types and reference types. Primitive types occupy very little memory, usually strings, numbers, and Boolean values, which are stored in the stack. Reference types can be arrays, ordinary objects or functions, and they generally contain more data, so the actual data of the reference type is stored in the heap of memory, and then an address pointing to the actual data is stored in the stack.

const str = "abc" // 原始类型
const obj = { foo: "bar" } // 引用类型

Every time a variable is declared in JS, the memory occupied by the application will increase accordingly, but the memory of the machine is limited, and the memory occupation cannot increase without limit. Therefore, the JS engine needs to reclaim memory in a timely manner, release memory, and retain performance, so that the program can run smoothly.

What kind of garbage will the garbage collection mechanism recycle?

When an object is not referenced by any references, it becomes unreachable, and the garbage collector needs to mark these unreachable objects as recyclable and reclaim their memory at the appropriate time.

Take the following code as an example:

function myFunction() {
  const obj = { foo: "bar" }
  // do something
}

myFunction()

objAfter the function is executed, the object in this code myFunctionis no longer referenced and needs to be recycled.

But when an object is no longer used from a development point of view, but it is still referenced somewhere unexpectedly, the garbage collector cannot reclaim its memory, which will cause a memory leak (memory gradually accumulates, and the program occupies More and more memory, when it exceeds the available memory of the system, it will cause the program to crash).

For example, the object in the following code objmay not be recycled:

function myFunction() {
  const obj = { foo: "bar" }

  setTimeout(() => {
    console.log(obj.foo)
  }, 1000)
}

myFunction()

因为 obj 作为闭包中的引用传递给了定时器的回调函数,即使 myFunction 执行完毕,由于定时器没有被清除,obj 仍然被定时器回调函数持有引用,就可能导致 obj 不会被垃圾回收。

垃圾回收的算法

JavaScript 中的垃圾回收机制主要基于以下两个原则:

引用计数(Reference Counting)

每个对象都有一个引用计数,用于记录有多少个引用指向该对象。当引用计数变为零时,表示没有任何引用指向该对象,因此该对象可以被回收。

标记-清除(Mark and Sweep)

这是一种更常见的垃圾回收算法。它从根对象(如全局对象、当前执行上下文中的变量等)开始,通过遍历对象之间的引用关系,标记所有可达的对象。然后,回收器会清除未标记的对象,即不可达的对象,释放其内存。

Chrome 和 nodejs 的垃圾回收算法

Chrome 和 nodejs 都采用了谷_歌开源的 V8 引擎。V8 引擎的垃圾回收机制采用了标记清除算法,但在此基础又做了一些优化。

V8 引擎将内存分为新生代(Young Generation)和老生代(Old Generation)。大多数对象在新生代中创建,经过一定时间后,如果它们仍然存活,就会被晋升到老生代。

Scavenger 垃圾回收(新生代)

新生代使用了 Scavenger 垃圾回收算法,它将内存划分为一个存活区域和一个空闲区域。对象首先被分配到存活区域,当存活区域满时,会执行垃圾回收操作,将存活的对象复制到空闲区域,并清空存活区域。

Mark-Sweep-Compact 垃圾回收(老生代)

老生代中使用了 Mark-Sweep-Compact(标记-清除-整理)垃圾回收算法。它首先标记所有的存活对象,然后清除掉未被标记的对象,最后进行内存整理,使存活对象连续排列,减少内存碎片。

增量垃圾回收

V8 引擎还支持增量垃圾回收。他会将垃圾回收操作分成多个小步骤执行,每个步骤之间会插入一些 JavaScript 代码的执行,从而避免长时间的垃圾回收造成的界面卡顿。

空闲时间垃圾回收

V8 引擎还在空闲时间执行部分垃圾回收操作,以充分利用闲置的计算资源。这些时间段可能是在程序等待用户输入、网络请求返回、或者其他暂时没有任务需要处理的情况下出现的。

需要手动清除的内存

垃圾回收机制会根据算法智能的回收大部分的内存,但由于业务逻辑的关系,它无法明确知道在我们的写的(垃圾)代码中,哪些对象其实是不再使用的,所以我们在开发过程中需要及时的清除不需要的事件监听、定时器、计时器,避免循环引用,以及避免使用闭包。

清除事件监听

const myButton = document.getElementById("myButton")

function handleClick() {
  console.log("Button clicked!")
}

// 添加事件监听器
myButton.addEventListener("click", handleClick)

// 在页面卸载或元素移除时解除事件监听器
window.addEventListener("beforeunload", () => {
  myButton.removeEventListener("click", handleClick)
})

执清除定时器、计时器

const timer = setTimeout(() => {}, 500)

// 在页面卸载或元素移除时解除事件监听器
window.addEventListener("beforeunload", () => {
  clearTimeout(timer)
})

手动调用垃圾回收

一般情况下我们无需手动调用垃圾回收,但有些浏览器支持主动触发垃圾回收。

IE 浏览器

if (typeof window.CollectGarbage === "function") {
  window.CollectGarbage()
}

Opera 浏览器

if (window.opera && typeof window.opera.collect === "function") {
  window.opera.collect()
}

本文转载于:

https://juejin.cn/post/7267434484505788468

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

Guess you like

Origin blog.csdn.net/qq_40716795/article/details/132332516