这是我参与8月更文挑战的第24天,活动详情查看:8月更文挑战
关于js的内存分配机制
js内存空间分为:栈,堆,池,栈用来存放变量,堆存放复杂对象,池存放常量。
-
js中基础数据类型,这些值都有固定的大小,往往保存在栈中(闭包除外),由系统自动分配存储空间。我们可以直接操作保存在栈内存空间的值,因此基础数据类型都是按照值来访问的,数据在栈内存中的存储与使用方式类似于数据结构中的堆栈数据结构,遵循后进先出的原则。
-
引用数据类型与堆内存:js中的引用数据类型大小是不固定的,引用数据类型的值时保存在堆内存中的对象。js不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际对象。保存在栈内存中的一个地址与堆内存的实际值相关联。
关于内存的生命周期
- 内存分配:当我们申请变量,函数,对象的时候,系统会自动为他们分配内存
- 内存使用:即读写内存,也就是使用变量、函数
- 内存回收:使用完毕,有垃圾回机制回收不再使用的内存
js垃圾回收机制
JS自带一套内存管理引擎,负责创建对象、销毁对象,以及垃圾回收。这期探讨一下垃圾回收机制。垃圾回收机制主要是由一个叫垃圾收集器(garbage collector,简称GC)的后台进程负责监控、清理对象,并及时回收空闲内存。
垃圾回收的必要性
每当创建一个实体时,都要动态分配内存,如果不释放,就会消耗完系统中所有可用的内存,造成系统崩溃。
垃圾回收方法
JS执行环境中的垃圾回收器怎样才能检测哪块内存可以被回收有两种方式:标记清除(mark and sweep)、引用计数(reference counting)。
标记清除(mark and sweep)
当变量进入执行环境(函数中声明变量)的时候,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”,在离开环境之后还有的变量则是需要被删除的变量。标记方式不定,可以是某个特殊位的反转或维护一个列表等。
垃圾收集器给内存中的所有变量都加上标记,然后去掉环境中的变量以及被环境中的变量引用的变量的标记。在此之后再被加上的标记的变量即为需要回收的变量,因为环境中的变量已经无法访问到这些变量。
function func () {
const a = 1 const b = 2 // 函数执行时,a b 分别被标记 进入环境
}
func() // 函数执行结束,a b 被标记 离开环境,被回收
引用计数(reference counting)
根据被引用的次数,当声明一个变量并将一个引用类型赋值给该变量时,这个值得引用次数就是1,相反,如果包含对这个值引用的变量又取得了另外一个值,这个值得引用次数就-1,当这个值得引用次数变为0的时候,就说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,就会释放哪些引用次数为0所占的内存。
这种方式常常会引起内存泄漏,低版本的IE使用这种方式。该方式会引起内存泄漏的原因是它不能解决循环引用的问题
function sample(){
var a={};
var b={};
a.prop = b;
b.prop = a;
}
这种情况下每次调用sample()函数,a和b的引用计数都是2,会使这部分内存永远不会被释放,即内存泄漏。
总结
JS的垃圾回收机制是为了以防内存泄漏,内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。