一文看懂前端垃圾回收

简介

javascript里面变量再也不使用,就是垃圾,咱们就应该把它清除掉,以避免占用内存。
可是垃圾回收过程是一个近似且不完美的方案,由于某块内存是否还有用,属于“不可断定的”问题,意味着靠算法是解决不了的。
目前主流浏览器使用的是标记清除,在介绍标记清除前先介绍下为何引用计数会被淘汰。javascript

引用计数

引用计数最先由 Netscape Navigator 3.0 采用,但很快就遇到了严重的问题:循环引用。
所谓循环引用,就是对象 A 有一个指针指向对象 B,而对象 B 也引用了对象 A。html

function problem() {
let objectA = new Object(); 
let objectB = new Object();
objectA.someOtherObject = objectB; 
objectB.anotherObject = objectA;
}

在这个例子中,objectA 和 objectB 经过各自的属性相互引用,意味着它们的引用数都是 2。在 标记清理策略下,这不是问题,由于在函数结束后,这两个对象都不在做用域中。而在引用计数策略下objectA 和 objectB 在函数结束后还会存在,由于它们的引用数永远不会变成 0。若是函数被屡次调 用,则会致使大量内存永远不会被释放。为此,Netscape 在 4.0 版放弃了引用计数,转而采用标记清理。前端

标记清除

  • 1.垃圾回收程序运行的时候,会标记内存中存储的全部变量。
  • 2.而后它会将全部在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉。
  • 3.在此以后再被加上标记的变量就是待删除的了,缘由是任何在上下文中的变量都访问不到它们了。

可达性

这里介绍下第二步骤的一个实现。
可达性就行可访问性,window(globle)能访问某个变量A(无论经过几层取值),那A就是可达的,那么A就有可能再将来会被用,A就不会被删除。
咱们看一下下图就能明白,左边可达,右边不可达,右边会再某个阶段会v8引擎回收
java

相关概念

闭包

明白了垃圾回收的概念,理解闭包就简单多了。
闭包为啥不销毁,由于当前函数执行完的返回值(通常是个函数)被外层上下文中的某个变量引用了,因此闭包中的环境可达,因此不会被销毁。
可是也由于不会被销毁,因此咱们应该注意一下内存泄漏,也就是若是闭包占用的内存特别多,又把它赋给全局变量。并且这个操做咱们是不断的进行的,那个内存就会越占越多,也就是发生了内存泄漏。es6

weakmap

还有个相关的考点,就是weakmap为何不会被gc(Garbage Collection,垃圾收集)
由于它对于值的引用都是不计入垃圾回收机制的,因此名字里面才会有一个"Weak",表示这是弱引用。
防止内存泄漏咱们须要手动置null。
map的键是对象,这个引用当于永远可达,这样很差,会有内存泄漏。
为了不咱们忘记置Null,es6添加了weakmap这种数据结构,只要所引用的对象的其余引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦再也不须要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用面试

性能优化

  • 经过 const 和 let 声明提高性能
    由于 const和 let 都以块(而非函数)为做用域,因此相比于使用 var,使用这两个新关键字可能会更早地让垃圾回收程序介入,尽早回收应该回收的内存。
  • 多解除引用(闭包)
    优化内存占用的最佳手段就是保证在执行代码时只保存必要的数据。若是数据再也不必要,那么把它设置为 null,从而释放其引用。这也能够叫 做解除引用。这个建议最适合全局变量和全局对象的属性。局部变量在超出做用域后会被自动解除引用,算法

    参考资料

    1.垃圾回收
    2.JavaScript 内存泄漏教程
    3.前端面试:谈谈 JS 垃圾回收机制
    4.MDN-内存管理
    5.javascript高级程序设计第4版本segmentfault

相关文章
相关标签/搜索