前端面试——JS垃圾回收机制

1.垃圾回收机制

https://www.cnblogs.com/zhwl/p/4664604.html

https://blog.csdn.net/oliver_web/article/details/53957021

https://blog.csdn.net/natsuyu/article/details/50864936

http://www.ruanyifeng.com/blog/2017/04/memory-leak.html

     (1)垃圾回收概述

      垃圾回收机制(GC:Garbage Collection),执行环境负责管理代码执行过程中使用的内存。垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。

    (2)垃圾回收策略:

        2种最为常用:标记清除和引用计数,其中标记清除更为常用。

  • 标记清除(mark-and-sweep):是对于脱离作用域的变量进行回收,当进入作用域时,进行标记,离开作用域时,标记并回收这些变量。到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。

         当变量进入环境(例如,在函数中声明一个变量)时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占的内存,因为只要执行流进入相应的环境,就可能用到它们。而当变量离开环境时,这将其 标记为“离开环境”。

  •  引用计数:引用计数是跟踪记录每个值被引用的次数。就是变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象,每当过一段时间开始垃圾回收的时候,就把被引用数为0的变量回收。引用计数方法可能导致循环引用,类似死锁,导致内存泄露。

  在这个例子中,objA和objB通过各自的属性相互引用;也就是说这两个对象的引用次数都是2。在采用引用计数的策略中,由于函数执行之后,这两个对象都离开了作用域,函数执行完成之后,objA和objB还将会继续存在,因为他们的引用次数永远不会是0。这样的相互引用如果说很大量的存在就会导致大量的内存泄露。

(3)常见内存泄露的原因

  • 全局变量引起的内存泄露
  • 闭包引起的内存泄露:慎用闭包
  • dom清空或删除时,事件未清除导致的内存泄漏
  • 循环引用带来的内存泄露

(4)如何减少垃圾回收开销

        由于每次的垃圾回收开销都相对较大,并且由于机制的一些不完善的地方,可能会导致内存泄露,我们可以利用一些方法减少垃圾回收,并且尽量避免循环引用

  • 在对象结束使用后 ,令obj = null。这样利于解除循环引用,使得无用变量及时被回收;
  • js中开辟空间的操作有new(), [ ], { }, function (){..}。最大限度的实现对象的重用;
  • 慎用闭包。闭包容易引起内存泄露。本来在函数返回之后,之前的空间都会被回收。但是由于闭包可能保存着函数内部变量的引用,且闭包在外部环境,就会导致函数内部的变量不能够销毁。

   (5)垃圾回收的缺陷

      和其他语言一样,javascript的GC策略也无法避免一个问题:GC时,停止响应其他操作,这是为了安全考虑。而Javascript的GC在100ms甚至以上,对一般的应用还好,但对于JS游戏,动画对连贯性要求比较高的应用,就麻烦了。这就是新引擎需要优化的点:避免GC造成的长时间停止响应。

   (6)优化GC

  • 分代回收(Generation GC):与Java回收策略思想是一致的。目的是通过区分“临时”与“持久”对象;多回收“临时对象”区(young generation),少回收“持久对象”区(tenured generation),减少每次需遍历的对象,从而减少每次GC的耗时。
  • 增量GC:这个方案的思想很简单,就是“每次处理一点,下次再处理一点,如此类推。

猜你喜欢

转载自blog.csdn.net/qq_21428081/article/details/82465801
今日推荐