JavaScript的垃圾回收机制
1.概述
1.1 什么是程序中的垃圾?
简单来说,垃圾就是不需要,已经没用的东西。对应程序中,就是当一个变量没有被其他变量或属性引用的时候,该变量就是程序中的垃圾了。那变量又分局部变量和全局变量,它们的生命周期是不同的,释放内存(垃圾回收)的判断也是不同的。
1.2 变量的生命周期
(1)全局变量:
描述:定义在所有函数之外的变量。
生命周期:会持续到浏览器关闭页面
(2)局部变量:
描述:定义在某个函数中的变量
生命周期:函数执行过后就结束了,此时便可释放它们占用的内存(垃圾回收)
1.3 数据存储
在Javascript中,基本数据类型存储在栈内存中,引用数据类型存储在堆内存中,但是引用数据类型会在栈内存中存储一个实际对象的引用。示例如下:
let num = 12;
let obj = {
name:'shier', age:'12'};
obj = [1,2,3,4];
变量obj和name的存储方式如下图:
如上图中所示粉色块内数据没有被引用变成了垃圾。
1.4 为什么需要垃圾回收
由于 JavaScript 是动态分配内存的语言,当创建变量、对象、函数等时,都会占用一定的内存。如果这些占用的内存长期不被释放,就会造成内存泄漏,最终可能导致程序崩溃或性能问题。因此,垃圾回收的核心作用就是自动检测不再使用的内存并释放它们,以保持程序的高效运行。
1.5 什么是垃圾回收
垃圾回收机制也称Garbage Collection简称GC。在JavaScript中拥有自动的垃圾回收机制,通过一些回收算法,找出不再使用引用的变量或属性,由JS引擎按照固定时间间隔周期性的释放其所占的内存空间。在C/C++中需要程序员手动完成垃圾回收。
1.6 垃圾回收机制会回收哪些垃圾?
当一个对象不在任何地方被引用时(如何判断是否被引用由算法决定,后面会介绍算法),垃圾回收器就需要将这些对象进行标记,并在适当的时机回收它们的内存。
以下面这段代码为例:
function myFunction() {
const obj = {
foo: "bar" }
// do something
}
myFunction()
这段代码中的 obj 对象在 myFunction 函数执行之后,就已经没有被引用了,就需要被回收。
但当某个对象从开发角度上来说不再被使用了,却意外的仍然在某个地方被引用,垃圾回收器就无法回收它的内存,就会造成内存泄漏(内存逐渐累积,程序占用的内存越来越多,当超过系统的可用内存时,就会造成程序崩溃)。
比如下面这段代码中 obj 对象就有可能不会被回收(取决于算法):
function myFunction() {
const obj = {
foo: "bar" }
setTimeout(() => {
console.log(obj.foo)
}, 1000)
}
myFunction()
因为 obj 作为闭包中的引用传递给了定时器的回调函数,即使 myFunction 执行完毕,由于定时器没有被清除,obj 仍然被定时器回调函数持有引用,就可能导致 obj 不会被垃圾回收。
2.垃圾回收策略
垃圾回收并不是实时的,因为开销比较大,所以垃圾回收器会周期性的释放程序中已经不在被引用的垃圾对象。 那如何判断哪些被引用了,哪些不再被引用?通常会使用以下方法来进行判断。
2.1 引用计数法
该算法的原理是,记录每个对象的引用次数,引用增加时计数器加一,引用减少时减一,当引用计数变为零时,就表示没有任何引用指向该对象了,该对象就可以被回收。
let a = {
name: "江流",
age