GC垃圾回收机制:
垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。
不再使用的变量即指那些局部变量,全局变量的生命周期直到浏览器关闭页面才结束,这时会再清除一次。
局部变量只在函数执行过程中存在,这个过程中会给它们分配内存去储存它们的值,然后在函数中使用,直至函数结束,而闭包是因为在函数外还有对这个变量的引用,所以并不会被垃圾回收机制清除。
标记清除法(常用):
垃圾回收器在运行的时候会给储存在内存里的所有变量都加上标记。然后去掉环境中的变量及被环境中的变量引用的变量的标记。在这之后还有标记的变量将被视为要删除的变量。最后,回收机制运行,销毁这些带标记的值并回收他们所占的内存空间。
例:
function mark(){
var a = 10; //被标记进入环境
var b = 20; //被标记进入环境
}
mark(); //执行完毕,a,b被标记离开环境
引用计数法:
跟踪记录每个值被引用的次数。声明一个变量且把一个引用数据类型赋给这个变量的时候,这个变量的引用次数+1,如果同个值再被赋给另外一个变量,引用次数再+1。相反,如果包含对这个值的引用的变量又被赋了另外一个值,它的引用次数就-1。引用次数为0时,将被认为是需要回收的值。
问题:循环引用时会造成互相引用的两个变量引用次数都不会为0,将不会被清除,造成内存泄漏。如果需要解决这种问题,则需要手动结束两个变量的互相引用,将变量设置为null。
例:
function cite(){
var a = 10;
var b = a; //a被引用,引用次数为1
var c = a; //a再次被引用,引用次数为2
b = {}; //b解除对a的引用,a的引用次数为1
}
GC机制的缺陷:
GC时会停止响应其他操作。
优化:
分代回收:
与Java的回收策略相似,即将对象分为“临时”与“持久”对象,多回收“临时”对象区,少回收“持久”对象区,这样减少了每次回收时判断遍历的个数,从而减少了每次GC的耗时。
增量回收:
每次处理一点,下次再处理一点,优点是减少了GC的耗时,但中断却较多。
内存分配:
javascript变量可以用来保存两种类型的值,基本类型值(undefined,null,boolean,number,string)和引用类型值(array,function,object)。
- 基本类型的值在内存中占据固定大小的空间,因此被保存在栈内存中,从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本。
- 引用类型的值是对象,保存在堆内存中。包含引用类型值的变量实际上包含的不是对象本身,而是一个指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终指向的是同一个对象,所以修改之前的值,之后复制的变量也会被修改,而这是我们不希望的,所以存在深浅复制的问题。js实现深浅复制
- 栈的优势就是存取速度比堆要快,存放在一级缓存中,仅次于直接位于CPU中的寄存器,但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
- 堆的优势是可以动态地分配内存大小,存在二级缓存中,生存期也不必事先告诉编译器,垃圾收集器会自动地收走这些不再使用的数据,比如对象和数组是可以无限拓展的,正好放在可以动态分配大小的堆中。但是缺点是由于在运行时动态分配内存,所以存取速度较慢。