zoukankan      html  css  js  c++  java
  • 垃圾收集机制

    JavaScript具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存。而C,C++之类的语言则会麻烦一些,需要手动跟踪内存的使用情况。
    但是在编写JavaScript代码的时候,大部分的时候,就不用再关心内存的问题,因为所需内存的分配以及无用内存的回收完全实现自动管理。
    这种垃圾回收机制的原理:找到不再继续使用的变量,然后释放它们占用的内存。所以,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间),周期性地执行这一操作。

    局部变量的正常生命周期

    局部变量只会在函数执行过程中存在,在这个过程中,会为局部变量再栈或者堆内存上分配相应的空间,以便存储它们的值。然后在函数中使用这些变量,直至函数执行结束。
    这种情况比较好判断变量的存在必要性,但在某些情况下就不容易判断,垃圾收集器必须跟踪哪个变量有用哪个变量没用,对于不再有用的变量打上标记,以备将来收回其占用内存。用于标识无用变量的策略可能会因实现而异,但具体到浏览器中的实现,则通常有两个策略。

    一、标记清除(常用)

    1.标记清除就是给变量做标记。当变量进入环境的时候,就将这个变量标记为“进入环境”。当变量离开环境的时候,将其标记为离开环境。
    可以用任何方式来标记变量,比如:

    • 可以通过翻转某个特殊的位来记录一个变量何时进入环境
    • 使用一个“进入环境的”变量列表
    • 使用一个“离开环境的”变量列表
      ....
      可以使用上述方法来跟踪那个变量发生了变化。有时候标记变量的方式不太重要,重要的是采取什么策略

    2.原理
    垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记,可以使用任何方式进行标记。然后它会去掉环境中的变量以及被环境中变量引用的变量的标记。在此之后再被加上标记的变量将被作为准备删除的变量。最后垃圾收集器会完成内存清除工作,即销毁那些带标记的值并回收它们所占用的内存空间。

    二、引用计数(不太常见)

    含义:跟踪记录每个值被引用的次数。
    当声明了一个变量并将一个引用类型值赋值给该变量,则这个值的引用次数加1,如果同一个值又被赋值给另一个变量,则该值的引用次数加1.相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1.当这个值的引用次数减为0的时候,就没有办法再访问它了,当垃圾收集器,下次运行的时候,就会释放那些引用次数为0的值所占用的内存。
    Netscape Navigator 3.0最早使用引用计数策略的浏览器,但遇到了一个严重的问题:循环引用

    • 定义:

    对象A中包含一个指向对象B的指针,对象B中也包含一个指向对象A的引用。

    • 举例
    function problem(){
        var objectA = new Object();
        var objectB = new Object();
    
        objectA.someOtherObject = objectB;
        objectB.anOtherObject = objectA; //objectA和objectB这两个对象的引用次数都为2.
    }
    

    上述如果使用标记清除就没有问题,引用计数就会出现循环引用的问题。
    后来Netscape Navigator 4.0放弃了引用计数清除策略,但是还是存在问题。

    BOM和DOM中的对象问题
    IE中有一部分对象并不是原生JavaScript对象。其BOM和DOM中的对象就是使用C++以COM(组件对象模型)对象的形式实现的,而COM对象的垃圾收集机制采用的就是引用计数策略。
    即使IE的JavaScript引擎是使用标记清除策略来实现的,但是JavaScript访问的COM对象依然是基于引用计数策略的,只要在IE中涉及COM对象,就会存在循环引用的问题。

    var element = document.getElementById("some_element");
    var myObject = new Object();
    myObject.element = element;
    element.someObject = myObject;
    //上面也出现 了循环引用的问题,为了避免这个问题,最好在不使用它们的时候手工断开原生JavaScript对象和DOM元素之间的连接。
    myObject.element = null;
    element.someObject = null;
    //这样就切断变量和它之前引用的值之间的连接。当垃圾收集器下次运行时就会删除这些值并回收它们占用的内存。
    

    但是为了解决这个问题,IE9把BOM和DOM对象都转换成了真正的JavaScript对象,这样避免了两种垃圾收集算法并存导致的问题,也消除了常见的内存泄漏的问题。

    性能问题

    垃圾收集器是周期运行的,确定垃圾收集器的时间间隔是一个非常重要的问题。之前IE的垃圾收集器是根据内存分配量运行的,具体一点:可以是256个变量、4096个对象字面量等等,只要达到上面任何一个临界值,垃圾收集器就会运行。
    存在的问题
    如果一个脚本中包含变量很多,那么脚本在它的生命周期中都一直保存这么多变量。这样的话,垃圾收集器就会不断地运行。结果,由此引发的严重性能问题导致IE7重写了垃圾收集例程。IE7中新的垃圾收集例程:当垃圾收集例程回收的内存分配量低于15%,那么变量、字面量等等的临界值就加倍,如果回收的内存分配量达到了85%,那么临界值重置会默认值。这样简单的设置,极大地提升了IE在运行时包含大量JavaScript的页面时的性能。

    管理内存

    分配给Web浏览器的可用内存数量通常比桌面应用程序的少,因为出于安全的考虑,目的防止运行JavaScript的网页耗尽全部系统内存而导致系统崩溃。优化内存占用的最佳方式,为执行中的代码只保留必要的数据,一旦数据不再有用,则将其值设置为null来释放其应用,即解除引用。这一做法大多适用于大多数全局变量和全局对象的属性。

  • 相关阅读:
    【POJ 1958】 Strange Towers of Hanoi
    【HNOI 2003】 激光炸弹
    【POJ 3263】 Tallest Cow
    【POJ 2689】 Prime Distance
    【POJ 2777】 Count Color
    【POJ 1995】 Raising Modulo Numbers
    【POJ 1845】 Sumdiv
    6月16日省中集训题解
    【TJOI 2018】数学计算
    【POJ 1275】 Cashier Employment
  • 原文地址:https://www.cnblogs.com/sminocence/p/8411156.html
Copyright © 2011-2022 走看看