Javascript 高级编程 4章78页 【垃圾收集】

124 阅读3分钟

垃圾收集

执行环境 会负责管理 代码执行过程中使用的内存

  • 内存的分配和无用内存的回收,完全实现了自动管理
  • 垃圾收集器:
    • 会按照固定的时间间隔(或代码中预定义的收集时间)来周期性地释放无用内存
    • 会给无用变量打上标记,以备将来回收
      • 标记无用变量的策略会因实现而异
      • 通常有两个策略:标记清除(mark-and-sweep)和引用技术(reference counting)

标记无用变量的策略: 标记清除

  • 最为常用
  • 标记变量是“进入环境”还是“离开环境”
  • 不同浏览器的回收时间间隔不同

标记无用变量的策略: 引用技术

引用类型的值:

  • 赋给一个变量时,引用次数+1
  • 包含这个值的变量被赋了其他值时,引用次数-1

垃圾回收器会释放那些引用次数为0的值所占的内存


但当有循环引用时,这种策略就会遇到麻烦,导致内存泄漏 以下例子中:

  • 两个引用类型的值的引用次数都为2
  • 但这个方法退出后,它们的引用次数都永远不会为0
//循环引用
function problem () 
{
    var objectA = new Object();
    var objectB = new Object();
    
    objectA.someOtherObject = objectB;
    objectB.anotherObject = objectA;
}

历史:

  • Netscape:
    • 最早开始使用引用技术策略,但在Navigator 4.0中也放弃了这一策略,转而使用标记清除策略
  • IE:
    • IE 9之前,有一部分对象不是原生的Javascript对象,例如BOMDOM (c++ com实现的,实际上用的是引用计数策略)
    • 因此,IE 9之前,即便IE的引擎是使用标记清除策略,但只要在IE中涉及COM对象,就会存在循环引用的问题
//DOM元素element和原生javascript对象myObject之间的循环引用
var element = document.getElementById("some_element");
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;

解决: 不用的时候,手动断开连接

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

垃圾收集时间间隔

  • 关于垃圾回收收集器多长时间运行一次,这让人想起IE因此而声明狼藉的性能问题
  • IE的垃圾收集器是根据内存分配量而运行的,达到以下任何一个临界值,垃圾收集器就会运行
    • 256个变量
    • 2096个对象字面量和数组元素
    • 64KB字符串
  • IE 7的Javascript引擎,重写了垃圾收集例程
    • 临界值会动态调整
    • 在运行包含大量Javascript的页面时,性能得到提升

在有的浏览器中,可以触发垃圾收集,但是不建议这么做

  • IE: window.CollectGarbage()
  • Opera7, window.opera.collect()

内存管理

系统分配给Web浏览器的可用内存数量,通常要比分配给桌面应用程序的少 目的:

  • 放置运行Javascript的网页耗尽全部系统内存,而导致系统崩溃 结果:
  • 影响给变量分配内存
  • 影响调用栈
  • 影响一个线程中能够同时执行的语句数量 因此,需要:

确保占用最少的内存,可以让页面获得更好的性能 优化内存占用的最佳方式:为执行中的代码只保存必要的数据

  • 一旦数据不再游泳,最好将其值设为null,来解除引用
  • 这适用于:
    • 大多数全局变量和全局变量的属性
  • 局部变量,会在离开执行环境是,自动被解除引用
function createPerson (name) {
    var localPerson = new Object();
    localPerson.name = name;
    //localPerson自动被解除引用
    return localPerson;
}
var globalPerson = createPerson("Nicholas");
globalPerson = null;