js之垃圾回收

JavaScript具有自动垃圾收集机制,即执行环境会负责管理代码执行过程中使用的内存。
原理:找出那些不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔,周期性的执行这一操作。

    函数中局部变量的正常生命周期:局部变量只在函数执行的过程中存在。在这个过程中为为局部变量 在栈(或堆)内存上分配相应的空间,以便存储他们的值,在函数中使用这些变量,函数执行结束后,局部变量便不再需要存在了,需要释放他们的内存等待将来使用,这种情况很容易判断变量是否有存在必要,但还有其他很多不容易判断的情况。因此,垃圾收集器必须跟踪哪个变量有用哪个变量没用,对于无用的变量打上标记,等待回收其占用的内存。

垃圾收集方法

  • 标记清除
  1. js中最常用的就是标记清除,当变量进入环境(比如在函数中声明一个变量)的时候,将变量标记为“进入环境”,进入环境的变量是不可能被释放的,因为只要执行流进入相应的环境,就有可能会使用到它们。当变量离开环境的时候,将变量标记为“离开环境”。(ps:可以用任何方式标记变量,比如翻转某个特殊的位,或者使用一个进入环境的变量列表以及一个离开环境的变量列表来跟踪变量。)
  2. 垃圾收集器在运行的时候会给所有的变量都加上标记,然后它会去掉环境中的变量以及被环境中变量引用的变量的标记,在此之后被加上标记的变量都将被认为准备删除的变量。原因是环境中的变量已经无法访问到这些变量。最后垃圾收集器完成内存清除工作,销毁带标记的值并回收它们所占用的内存空间。
  • 引用计数
  1. 引用计数的含义是跟踪记录每个值被引用的次数,声明一个变量,并将一个引用类型值赋给该变量时,这个值的引用次数就是1,如果同一个值又被赋给其他变量,则该值得引用次数加1,相反,包含这个值引用得变量又取得了另外一个值,则该值引用次数减1,当引用次数变为0时,说明没有办法再访问这个值了,这时需要将其回收。这样当垃圾收集器下次运行的时候,就会释放那些引用次数为0的值所占用的内存。
  2. 缺陷:会造成循环引用的问题
//循环引用指:对象A包含一个指向对象B的指针,而对象B中也包含一个指向对象A的引用。
function problem(){
    var objectA = new Object();
    var objectB = new Object();
    objectA.someOtherObject = objectB;
    objectB.anotherObject = objectA;
}

objectA和objectB通过各自属性互相引用,这两个对象的引用次数都为2,利用标记清除策略,函数执行后,这两个对象都离开了作用域,因此这种相互引用不算问题,但是引用计数策略,函数执行完毕后,objectA和objectB还会继续存在,因为它的引用次数永远不会是0,如果这个函数被重复多次调用,就会导致大量内存得不到回收。

3.因此后来采用了标记清除策略,,但是ie中一部分对象不是原生js对象,例如BOM和DOM中的对象就是使用c++以COM对象形式实现。com对象的垃圾收集机制采用的仍然为引用计数,因此,只要IE中涉及COM对象,都会存在循环引用的问题。
例如如下示列:

var element document.getElementById("some_element");
var myObject = new Object();
myObject.element = elemnet;
element.someObject = myObject;

//myObject和element存在循环引用,所以永远不会回收。

解决方法:在不使用他们的时候手工断开原生js对象与DOM元素之间的连接
添加下列代码消除循环引用即可

myObject.element = null;
element.someObject = null;

但是上述这些问题,在IE9中得到了解决,IE9把DOM和BOM对象转换成了真正的js对象,这样就解决了两种垃圾收集算法并存导致的问题,也消除了常见的内存泄露现象。

性能问题

  1. 垃圾收集机制是周期性运行的,如果为变量分配的内存数量非常可观,那么回收工作量也是相当大的。因此,确定垃圾回收时间间隔是非常重要的。
    IE的垃圾收集器是根据内存分配量运行的(256个变量4096个对象字面量和数组元素或者64kb的字符串),达到上述的任意一个临界值,垃圾收集器就会运行。
  2. 最开始的IE这种方式存在缺陷的,如果一个脚本中包含那么多的变量,很可能会在其生命周期中一直存在这么多变量,这样垃圾收集器就会频繁运行,导致产生性能问题
  3. IE7之后,js的垃圾收集改变了工作方式,触发垃圾收集的变量分配字面量或数组元素的临界值被调整为动态修正。如果垃圾收集例程回收的内存分配量低于15%则临界值翻倍,如果回收超过85%的内存分配量,临界值就会重置为默认值,这种方式极大的提高了页面性能。

管理内存

  1. 分配给web浏览器的可用内存数量低于分配给桌面应用程序的数量,目的是为了防止运行js的网页耗尽全部系统内存而导致系统崩溃。内存限制问题不仅会影响给变量分配内存,也会影响调用栈以及在一个线程中能够同时执行的语句数量。
  2. 因此为了确保占用最少的内存可以使页面获取更好的性能,优化内存的最佳方式,就是为执行的代码只保存必要的数据,如果数据无用,就将其设置为null,释放其引用,就是解除引用
    例如:
function A(name){
    var a = new Object();
    a.name = name;
    return a;
}
var b = A("hello");
//手工解除引用
b = null;

变量b取得了A()函数返回值,在函数内部,我们创建了一个对象并赋值给a,然后为该对象添加一个name属性,最后调用函数时,a以函数值得形式返回并赋给全局变量b,a在A()函数执行完毕后就离开了执行环境,则会被标记清除,但是对于全局变量b而言,我们需要手工解除引用。

解除引用不意味着自动回收该值所占用得内存,解除引用得真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收

发布了29 篇原创文章 · 获赞 59 · 访问量 8695

猜你喜欢

转载自blog.csdn.net/weixin_42878211/article/details/105211472
今日推荐