内存管理简介
像C语言这样的底层语言一般都有底层的内存管理接口,比如 malloc()和free()。相反,JavaScript是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。 释放的过程称为垃圾回收。这个“自动”是混乱的根源,并让JavaScript(和其他高级语言)开发者错误的感觉他们可以不关心内存管理。
谈到这里就不得不提到js垃圾回收机制:
js的垃圾回收机制(针对的是内存说的)
说的是:什么样的数据是没用的数据;没用的数据将被销毁;销毁的是堆中的数据。
在内存中分栈和堆。栈是系统创建 堆是程序员创建。如果不能合理的分配使用内存;会导致内存泄露 。
内存的生命周期:(底层语言)
1 分配你所需要的内存; (分空间)
2:使用配置你所需要的内存(读,写} (用空间;放东西,取东西)
3:不需要时候;将其释放 (所谓的垃圾回收机制)(对于很久都不用的东西;计算机会删除)
所有语言第二部分都是明确的。第一和第三部分在底层语言中是明确的,但在像JavaScript这些高级语言中,大部分都是隐含的。
JavaScript 的内存分配
值的初始化
为了不让程序员费心分配内存,JavaScript 在定义变量时就完成了内存分配:
var n = 123; // 给数值变量分配内存
var s = "azerty"; // 给字符串分配内存
var o = {
a: 1,
b: null
}; // 给对象及其包含的值分配内存
// 给数组及其包含的值分配内存(就像对象一样)
var a = [1, null, "abra"];
function f(a){
return a + 2;
} // 给函数(可调用的对象)分配内存
// 函数表达式也能分配一个对象
someElement.addEventListener('click', function(){
someElement.style.backgroundColor = 'blue';
}, false);
通过函数调用分配内存
有些函数调用结果是分配对象内存:
var d = new Date(); // 分配一个 Date 对象
var e = document.createElement('div'); // 分配一个 DOM 元素
有些方法分配新变量或者新对象:
var s = "azerty";
var s2 = s.substr(0, 3); // s2 是一个新的字符串
// 因为字符串是不变量,
// JavaScript 可能决定不分配内存,
// 只是存储了 [0-3] 的范围。
var a = ["ouais ouais", "nan nan"];
var a2 = ["generation", "nan nan"];
var a3 = a.concat(a2);
// 新数组有四个元素,是 a 连接 a2 的结果
使用值
使用值的过程实际上是对分配内存进行读取与写入的操作。读取与写入可能是写入一个变量或者一个对象的属性值,甚至传递函数的参数。
当内存不再需要使用时释放
大多数内存管理的问题都在这个阶段。在这里最艰难的任务是找到“哪些被分配的内存确实已经不再需要了”。它往往要求开发人员来确定在程序中哪一块内存不再需要并且释放它。
高级语言解释器嵌入了“垃圾回收器”,它的主要工作是跟踪内存的分配和使用,以便当分配的内存不再使用时,自动释放它。这只能是一个近似的过程,因为要知道是否仍然需要某块内存是无法判定的(无法通过某种算法解决)。
垃圾回收
引用
分类:显示引用和隐式引用。
显示引用:一个对象访问另一个对象下属性,
一个对象引用另一个对象。
隐式引用:一个对象,通过原型对象访问的属性。
对象指的是:GO,AO,函数对象,普通对象。
引用计数垃圾手机
关键看,一个对象是否被其他变量所引用(使用)
零引用的对象被垃圾回收机制所回收
下面举个例子:
var o = {
a:{
b:2,
},
};
两个对象,一个key为a,一个key为b
两个对象被创建,一个作为另一个的属性被引用,另一个被分配给变量o
很显然,没有一个可以被垃圾收集
var o2 = o; // o2变量是第二个对“这个对象”的引用
o = 1; // 现在,“这个对象”只有一个o2变量的引用了,“这个对象”的原始引用o已经没有
var oa = o2.a; // 引用“这个对象”的a属性
// 现在,“这个对象”有两个引用了,一个是o2,一个是oa
o2 = "yo"; // 虽然最初的对象现在已经是零引用了,可以被垃圾回收了
// 但是它的属性a的对象还在被oa引用,所以还不能回收
oa = null; // a属性的那个对象现在也是零引用了
// 它可以被垃圾回收了
总结:代码从头执行到尾,如果这个对象以及对象中属性没有被任何全局变量所引用,那么这个对象就会被回收。
循环引用
(学术观点不同),浏览器底层处理方式不同,IE6和7认为内存泄漏
(符合引用计算垃圾算你发),其他浏览器可能用的事循环引用算法和引用算法。
标记-清除算法
function foo(){
var a = 0;
return function(){
console.log(++a);
}
}
// 因为res引用的return返回的函数
// 在res执行的时候,需要引用foo的ao对象下的a属性
// 所以foo的ao对象不会被回收
var res = foo;
res();
res();
// 当闭包完成任务后
// 找到完成任务的条件,然后清空res,那么foo的ao对象就不会再被引用
// 所以实现了清空闭包的缓存
res = null;
// foo中的Ao会被回收
foo()() // 因为没有任何变量和属性,引用return返回的函数,所以ao回收