3、js - 面试 - 垃圾回收机制

1、基础概念

(1)js内存的生命周期

-1- 内存分配:当声明变量、函数、对象时,系统会自动分配内存给它们

-2- 内存使用:即读写内存,也就是使用变量、函数

-3- 内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存

(2)垃圾回收机制(Garbage Collection)简称GC

js的垃圾回收机制是一种内存管理技术,对开发者来说,js的垃圾回收机制是自动的、无形的。

我们创建的原始值、对象、函数……这一切都会占用内存,而在js引擎中有一个垃圾回收器在后台执行。

注意:全局变量一般不会回收(关闭页面时回收);一般情况下局部变量的值,不用了,会被自动回收掉。

2、已过时的垃圾收集算法 - 引用计数法

(1)引用计数法原理

主要看当前创建的对象在堆内存中有没有被其他对象引用,如果没有被其他对象引用,那么该对象将被垃圾回收机制回收。

let obj1 = { name: 'test'}; // 创建一个对象,被obj1所引用,计数为1
let obj2 = obj1; // obj2变量是第二个对该对象的引用,计数为2
obj1 = null; // 该对象的原始引用obj1已经没有了,计数为1
obj2 = null; // 此时对象所有引用都没有了,计数为0,垃圾回收机制回收该对象

(2)致命缺点:循环引用

两个对象内的属性相互引用对象,两个对象的引用计数永远大于0,无法回收导致内存泄漏

function func(){
    let obj1 = {};
    let obj2 = {};
    obj1.a = obj2;
    obj2.a = obj1;
    return 1;
}

在2012年以后所有现代浏览器都取消这种算法了,取而代之的是标记清除法。

3、标记清除法(mark-and-sweep)

2012年起,所有现代浏览器都使用了标记清除法

(1)标记清除法原理

它会定期执行以下“垃圾回收”步骤:

例如,对象有如下的结构:

3、js - 面试 - 垃圾回收机制_第1张图片

第一步,标记所有的根

下面列出固有的可达值的基本集合, 这些值明显不能被释放
比方说:
->当前执行的函数,它的局部变量和参数。
->当前嵌套调用链上的其他函数、它们的局部变量和参数。
->全局变量。
->(还有一些内部的)
这些值被称作 (roots)
3、js - 面试 - 垃圾回收机制_第2张图片

第二步,跟随根的引用标记它们所引用的对象

3、js - 面试 - 垃圾回收机制_第3张图片

第三步,……如果还有引用的话,继续标记

3、js - 面试 - 垃圾回收机制_第4张图片

最后,通过这个过程没有被标记的对象被认为是不可达的,并且会被删除

3、js - 面试 - 垃圾回收机制_第5张图片

关于垃圾回收,js引擎做了许多优化,使垃圾回收运行速度更快,也使得现代浏览器的性能越来越高,并且不会对代码执行引入任何延迟。

(2)垃圾收集机制的一些优化建议

  • 分代收集(Generational collection)—— 对象被分成两组:“新的”和“旧的”。在典型的代码中,许多对象的生命周期都很短:它们出现、完成它们的工作并很快死去,因此在这种情况下跟踪新对象并将其从内存中清除是有意义的。那些长期存活的对象会变得“老旧”,并且被检查的频次也会降低。

  • 增量收集(Incremental collection)—— 如果有许多对象,并且我们试图一次遍历并标记整个对象集,则可能需要一些时间,并在执行过程中带来明显的延迟。因此,引擎将现有的整个对象集拆分为多个部分,然后将这些部分逐一清除。这样就会有很多小型的垃圾收集,而不是一个大型的。这需要它们之间有额外的标记来追踪变化,但是这样会带来许多微小的延迟而不是一个大的延迟。

  • 闲时收集(Idle-time collection)—— 垃圾收集器只会在 CPU 空闲时尝试运行,以减少可能对代码执行的影响。

你可能感兴趣的:(前端框架,前端,javascript,ecmascript)