您的位置:首页 > Web前端 > JavaScript

js 内存管理机制

2013-03-18 21:44 148 查看
why?

js 具有自动垃圾回收机制,不用人工手动删除。既然这样,为什么还要关注js 内存管理机制呢?

1 最近在项目中,由于setInterval 和 闭包的使用,导致对象没有清除,带来很多性能上面的问题,如果能理解浏览器js 对象管理机制,将有效避免问题的出现

2 受限无移动设备的性能问题,很多在pc上没有问题的程序,在ipad等移动设备上面运行,也许运行过一段时间后,ipad直接跳出浏览器,终止了你的程序。这种情况就说明你程序有严重的内存泄露,IOS认为你的程序存在风险,终止了你的程序。可见开发移动应用,需要我们关注js内存管理机制

what?

简单的说,js是这样管理内存的

找出那些不再继续使用的变量,然后释放其中占用的内存。为此,垃圾收集器会按照固定的时间间隔(或代码执行中预设的收集时间),周期性的执行这一操作。

找出不再使用的变量,有以下两种方式:

1 标记清除 (主流做法)

javascript中最常用的垃圾收集方式是标记清除(mark-and-sweep)。当变量进入环境(例如,在函数中声明一个变量)时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占的内存,因为只要执行流进入相应的环境,就可能用到它们。而当变量离开环境时,这将其标记为“离开环境”。

2 引用计数法,跟踪记录每个值的被引用次数。

声明一个变量并将一个引用类型值赋给该变量时,这个值得引用次数就是 1。如果同一个值又被赋给另外一个变量,则该值的引用次数加 1。相反,如果包含对这个值的引用的变量又取得另外一个值,这个值得引用次数减 1。当这个值得引用次数为 0 时,则说明没有办法再访问到此值,因此就可以将其占用的内存空间回收。当垃圾收集器在下一个周期运行时,会释放引用次数为零的值所占用的内存空间。

一个严重的问题:循环引用。循环引用指的是对象A中包含一个指向对象B的引用,而对象B中也包含一个指向对象A的引用。



举个例子来说:

function problem(){

var object1 = new Object(); // 声明变量,计数器由 0 变为 1

var object2 = new Object(); // 声明变量,计数器由 0 变为 1

object1.method1 = object2; // object1 计数器 -1,object2 计数器 +1

object2.method2 = object1; // object1 计数器 +1,object2 计数器 -1

}

采用标记法,因为变量离开了他们的执行环境,他们会在下一个垃圾回收周期中被清除掉。so,现在的浏览器都采用标记法作为内存管理的策略。

查看很多其他资料,经常能看到下面的话:

JavaScript包含一个垃圾回收的小程序,这个程序能够周期性的遍历JavaScript环境中的所有变量的列表,并且给这些变量所引用的值做个标记。
如果被引用的值是对象或数组,那么对象的属性或者数组的元素就会被递归地做个标记。通过递归遍历所有值的树或者图,垃圾回收器就能够找到(并标记)仍旧使用的每个值。那些没有标记的值就是无用的存储单元。
当给所有正在使用的变量做完标记之后,垃圾回收器就会开始进行清除。在这个阶段中,它将遍历环境中所有值的列表,同时释放那些没有标记的值。
所以,关键问题是看,当前对该变量的引用计数为多少,如果有任何引用,那即使是临时变量也不会被立即回收的。闭包是借用了这一点。

咋看起来,像是在说浏览器采用引用计数的方式进行内存回收。
我们把上面循环引用的方法,在浏览器中跑一下,通过chrome 的profiles 中的 take heap snapshot 做实验,发现运行完毕,在内存中不存在那两个object 对象,实验证明,浏览器的确是用标记法,不是用引用的方法作为回收策略。那么上面的话,如何解释呢?

通过查看资料,可以这样理解。引用扩大了变量的执行环境,消除引用时,减小执行环境。当变量广义的执行环境退出时,变量将在垃圾回收机制中收回。

null 和 delete 的区别
他们分别做一下一件事情:
null : 解除引用。当对象的应用为o时,在内存回收周期中,收回内存(不是立即收回,浏览器每隔一段时间检查一次)
delete : 删除属性
注意:delete 同c++ 中delete 的区别

// C++

class Object {

public:

Object *x;

}

Object o;

o.x = new Object();

delete o.x; // 上一行new的Object对象将被释放

但Javascript的delete与C++不同,它不会删除o.x指向的对象,而是删除o.x属性本身。

var
o = {};

var a = { x: 10 };

o.a = a;

delete o.a; // o.a属性被删除

o.a; // undefined

a.x; // 10, 因为{ x: 10 } 对象依然被 a 引用,所以不会被回收

参考: http://huangyunbin.iteye.com/blog/1652270 http://blog.csdn.net/misol/article/details/6425063 http://bbs.phpchina.com/thread-221214-1-1.html http://www.alloyteam.com/2012/11/performance-writing-efficient-javascript/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: