一 内存管理
程序的运行需要内存。只要程序提出要求,操作系统或者运行时(
runtime
)就必须供给内存。对于JavaScript来说,有栈内存(
stack
)和堆内存(
heap
)。
对于持续运行的服务进程(daemon
),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak
)。
有些语言(比如 C 语言)必须手动释放内存,程序员负责内存管理。
char * buffer;
buffer = (char*) malloc(42);
// Do something with buffer
free(buffer);
上面是 C
语言代码,malloc
方法用来申请内存,使用完毕之后,必须自己用free
方法释放内存。
这很麻烦,所以大多数语言提供自动内存管理,减轻程序员的负担,这被称为”垃圾回收机制“(garbage collector)。
二 内存生命周期
- 分配需要的内存
- 使用它(读、写)
- 当它不使用时释放
三 js中的垃圾回收机制
- 最常用的:标记清除,“对象不再需要”定义为“对象是否可以获得”
- 引用计数,“对象不再需要”定义为“没有其他对象引用到它”
问题:循环引用
function problem(){
var obj1=new Object();
var obj2=new Object();
obj1.a=obj2;
obj2.a=obj1;
}
problem();
在上述代码中,函数problem调用后,obj1,obj2已经不再需要了,但是由于obj1与obj2相互引用,它们的引用次数至少为1,所以它们不会被回收。
IE中的BOM和DOM中的对象是以C++
以COM
(组件对象模型)的形式实现的,而COM对象的垃圾收集机制采用的就是引用计数。即使IE的JavaScript引擎是使用的标记清除来实现的,JavaScript对象依然是基于引用计数策略的。所以存在循环引用的问题。
var element=document.getElementById("id");
var obj=new Object();
obj.element=element;
element.someObject=obj;
上述代码中,DOM元素和一个原生JavaScript对象相互引用。由于循环引用,即使将该DOM从该页面中移除,它也永远不会被回收。
怎么解决?手动断开原生JavaScript与DOM元素之间的连接。
obj.element=null;
element.someObject=null;
手动断开后,当垃圾收集机制再次运行时会删除这些值并回收它们的内存。
IE9
把BOM
和DOM
对象都转换成了真正的JavaScript对象。
四 常见的内存泄漏的方式
- 意外的全局变量(变量未声明直接复制,this对象)
- 被遗忘的计时器或者回调函数
- 没有清除的DOM对象的引用
- 闭包
五 调试工具
可以通过Chrome Debug Tool来查看
- timeline 可以检测代码中不需要的内存。
- profiles 可以记录当前的堆内存(heap)快照,并生成描述文件。