JS垃圾回收的原理很简单:找出不再使用的变量,然后释放他占用的内存。垃圾收集器会按照固定的时间间隔,周期的执行这一操作。常用的标识无用变量的方式有如下两种:
1. 标记清除
2. 引用计数
1. 标记清除
标记清除是最常见的垃圾回收策略。
当变量进入环境时,将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。标记为“离开环境”的被回收。
- 垃圾回收器在运行的时候会给存储在内存中的所有变量都加上标记。
- 去掉环境中的变量以及被环境中的变量引用的变量的标记。
- 再被加上标记的会被视为准备删除的变量。
- 垃圾回收器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间。
注:2012年后所有现代浏览器均采用标记清除策略了
2. 引用计数
引用计数是不太常见的一个策略。
他是跟踪记录每个值被引用的次数。当值的引用次数变为0时,回收其内存。
- 声明了一个变量并将一个引用类型的值赋值给这个变量,这个引用类型值的引用次数就是1。
- 同一个值又被赋值给另一个变量,这个引用类型值的引用次数加1.
- 当包含这个引用类型值的变量又被赋值成另一个值了,那么这个引用类型值的引用次数减1.
- 当引用次数变成0时,说明没办法访问这个值了。
- 当垃圾收集器下一次运行时,它就会释放引用次数是0的值所占的内存。
循环引用的情况下,引用计数无法清除内存,导致内存泄漏。
3、内存分配
栈:在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。在栈中分配的内存,由系统自动管理释放。
堆:堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由虚拟机自动垃圾回收器来管理。
Javascript数据类型分为基本数据类型和引用数据类型:
基本数据类型包括:Number、String、Boolean、Null、Undefined。他们的值保存在栈的简单数据段中。
引用类型就是对象类型,比如Object 、Array 、Function 、Data等。他们的值保存在堆内存中。值得注意的是,我们不可以直接访问堆内存空间中的位置和操作堆内存空间。只能操作对象在栈内存中的引用地址。因此,栈内存中同时会保存着对象的引用地址,通过该地址访问堆内存的对象。