一、内存生命周期
1、分配需要的内存(初始化值时)
2、使用分配的内存
3、不需要时将其内存释放(垃圾回收器)
注意:
(1)全局变量的生命周期直至浏览器卸载页面才会结束。
(2)局部变量只在函数的执行过程中存在,而在这个过程中会为局部变量在栈或堆上分配相应的空间,以存储它们的值,然后再函数中使用这些变量直至函数结束局部变量就没有存在必要了,可以释放它们占用的内存
二、垃圾回收机制
1、引用计数垃圾收集
(1)算法原理
通过在对象头中分配一个空间来保存该对象被引用的次数。如果该对象被其它对象引用,则它的引用计数加一,如果删除对该对象的引用,那么它的引用计数就减一,当该对象的引用计数为0时,那么该对象就会被回收。
(2)算法理解
var p = new String("abc"); // 分配所需内存并且被p引用 abc这个字符串对象的引用计数值为1.
p = null; // 去除abc字符串对象的引用,abc字符串对象的引用计数减1
重点理解
1、当对象的引用发生变化时,首先对原来引用对象的计数减一,再对新的引用对象的计数加一
var p = new String("abc");
var q = new String("efd");
p = q;
2、当某个对象的引用计数减为0时,collector需要递归遍历它所指向的所有域,将它所有域所指向的对象的引用计数都减一,然后才能回收当前对象。在递归过程中,引用计数为0的对象也都将被回收,并把该对象的内存块加入空闲链表中
var p = {
phone:new String("1592xxxx"),
address:new String("1130 kifer rd")
}
p = null;
3、循环引用
function f(){
var o = {};
var o2 = {};
o.a = o2; // o 引用 o2
o2.a = o; // o2 引用 o
return "azerty";
}
f();
(3)触发时机
引用计数垃圾收集机制在引用计数变化为0时即刻发生,而且只针对某一个对象以及它所依赖的其它对象。所以,我们一般也称呼引用计数垃圾收集为直接的垃圾收集机制
2、标记-清除算法
(1)算法原理
这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。
标记阶段是把所有活动对象都做上标记的阶段。清除阶段是把那些没有标记的对象,也就是非活动对象回收的阶段。通过这两个阶段,就可以令不能利用的内存空间重新得到利用
这个算法假定设置一个叫做根(root)的对象(在Javascript里,根是全局对象)。垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象。
(2)算法理解
var teacher = {name:'Mary',age:35};
var student = {
stu1:{name:'Amy',age:13},
stu2:{name:'Dai',age:15}
}
标记阶段
// 标记阶段伪代码
// 进行标记阶段的处理
mark_phase(){
for(r : $roots)
mark(*r)
}
// 递归地标记通过指针数组能访问到的对象。这样就能把所有活动对象都标记上了。
mark(obj){
if(obj.mark == FALSE)
obj.mark = TRUE
for(child : children(obj))
mark(*child)
}
清除阶段
// 标记清除伪代码
1 sweep_phase(){
2 sweeping = $heap_start // 从堆首地址开始
3 while(sweeping < $heap_end) // 遍历每个标志位
4 if(sweeping.mark == TRUE) // 如果遍历到已标记元素
5 sweeping.mark = FALSE // 将标记清除
6 else // 没有遍历到
7 sweeping.next = $free_list // 将其插在空闲链表头部
8 $free_list = sweeping // 将空闲链表指针指向所有空闲链
9 sweeping += sweeping.size // 继续进行查找
10 }
(3)触发时机
垃圾收集器会按照固定的时间间隔或代码执行中预定的收集时间,周期性地执行
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。