[JS]JS内存管理

来源:互联网 发布:2万钱网络大电影 编辑:程序博客网 时间:2024/06/05 11:40

内存的生命周期

JS环境中分配的内存一般有如下生命周期:
  1. 内存分配:当我们申明变量、函数、对象的时候,系统会自动为他们分配内存
  2. 内存使用:即读写内存,也就是使用变量、函数等
  3. 内存回收:使用完毕,由垃圾回收自动回收不再使用的内存
内存分配的几个例子:
// 为变量分配内存var i = 11;var s = "ifcode";// 为对象分配内存var person = {    age: 22,    name: 'ifcode'};// 为函数分配内存function sum(a, b) {    return a + b;}//通过函数调用的内存分配var s = "azerty";  var s2 = s.substr(0, 3); // s2 is a new string  //因为string是不变量,JavaScript可能没有分配内存,但只是存储了0-3的范围。   var a = ["ouais ouais", "nan nan"];  var a2 = ["generation", "nan nan"];  var a3 = a.concat(a2); // 新数组中有连接数组a和数组a2中的四个元素。

垃圾回收算法

对垃圾回收算法来说,核心思想就是如何判断内存已经不再使用了。下面介绍两种常见浏览器的垃圾回收算法。

引用计数算法

熟悉C语言的同学的都明白,引用无非就是指向某一物体的指针。
引用计数算法定义“内存不再使用”的标准很简单,就是看一个对象是否有指向它的引用。如果没有其他对象指向它了,说明该对象已经不再需了。这是最简单的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。
// 创建一个对象person,他有两个指向属性age和name的引用var person = {    age: 22,    name: 'ifcode'};person.name = null; // 虽然设置为null,但因为person对象还有指向name的引用,因此name不会回收var p = person;person = 1;         //原来的person对象被赋值为1,但因为有新引用p指向原person对象,因此它不会被回收p = null;           //原person对象已经没有引用,很快会被回收
由上面可以看出,引用计数算法是个简单有效的算法。但它却存在一个致命的问题:循环引用。如果两个对象相互引用,尽管他们已不再使用,垃圾回收器不会进行回收,导致内存泄露。
    function f(){        var o = {};        var o2 = {};        o.a = o2; // o 引用 o2        o2.a = o; // o2 引用 o              return "azerty";      }            f();      // 两个对象被创建,并互相引用,形成了一个循环      // 他们被调用之后不会离开函数作用域      // 所以他们已经没有用了,可以被回收了      // 然而,引用计数算法考虑到他们互相都有至少一次引用,所以他们不会被回收
但根据引用计数的原则,他们之间的相互引用依然存在,因此这部分内存不会被回收,内存泄露不可避免了。正是因为有这个严重的缺点,这个算法在现代浏览器中已经被下面要介绍的标记清除算法所取代了。但绝不可认为该问题已经不再存在了,因为还占有大量市场的IE6、IE7使用的正是这一算法。

标记清除算法

这个“Mark And Sweep”算法把“对象是否不再需要”简化定义为“对象是否可以获得”。
上面说过,现代的浏览器已经不再使用引用计数算法了。现代浏览器通用的大多是基于标记清除算法的某些改进算法,总体思想都是一致的。

标记清除算法将“不再使用的对象”定义为“无法达到的对象”。简单来说,就是从根部(在JS中就是全局对象)出发定时扫描内存中的对象。凡是能从根部到达的对象,都是还需要使用的。那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收。从这个概念可以看出,无法触及的对象包含了没有引用的对象这个概念(没有任何引用的对象也是无法触及的对象)。

[Lua]Lua内存泄露检测原理
0 0
原创粉丝点击