一、垃圾回收相关概念
垃圾: 没有被引用的对象,就是垃圾对象。
垃圾回收:
- 销毁垃圾对象,释放内存,称为垃圾回收。
- 像C、C++ 等编程语言需要手动回收垃圾。
- 像Paython、JavaScript、Java 等编程语言自动回收。
何时会被回收?
- 修改变量的值,导致变量不再指向某个对象,该对象变为垃圾
- 代码执行结束,变量自动销毁,原来所指向的对象不再被引用,变为垃圾。
二、垃圾没有及时回收的后果
- 垃圾对象没有被清除,导致内存空间被占用, 造成内存泄漏。
- 内存空间越占越多,导致程序卡顿甚至死机。
三、JavaScript 垃圾回收的常见算法
- 引用计数
- 标记清除
3.1、引用计数(现在很少使用)
原理
- 每个对象都有一个引用标记
- 增加对该对象的引用(给变量或属性赋值),该对象的引用标记+1
- 减少对该对象的引用(变量或属性该值,变量属性被销毁),该对象的引用标记-1
- 当引用标记为 0 的时候,该对象变为垃圾对象,被回收
var a = [10, 20, 30, 40]; // 此时数组的引用计数是 1
var b = a; // 数组引用计数变为 2
a = null; // 修改变量 a 的值; 数组的引用计数变为 1
b = 10000; // 修改变量 b 的值; 数组的引用技术变为0,被销毁
// 直接量 用完即销毁
[1000, 2000, 3000, 4000, 6000];
优缺点:
- 垃圾回收及时,计算效率高
- 互相引用的两个对象,会永远无法被销毁,常驻内存,造成内存泄漏
var obj1 = { name: "x" }; // x引用计数是 1
var obj2 = { name: "y" }; // y的引用计数是 1
obj1.child = obj2; // y引用计数是 2
obj2.child = obj1; // x的引用计数是 2
// 修改变量 obj1的值; x引用计数是 1
// obj1 = null;
// 修改变量 obj2 的值; y的引用计数 1
// obj2 = null;
3.2、标记清除(常用)
原理
- 系统不断循环执行标记清除操作
- 每次标记清除分为两个阶段:
a:标记阶段:从全局对象开始,向下遍历属性以及属性的属性(树状递归遍历),能够访问到的对象,进行标记,称为可访问对象。
b:清除阶段:线性遍历内存中所有的对象,将没有标记的对象就是垃圾,进行回收。 - 下一轮去掉所有对象的标记,进行重新标记清除
优缺点
- 所有的垃圾对象都可以被回收,不会造成内存泄漏
- 不停地循环进行进行树状递归遍历,执行效率相对较低
var obj1 = { name: "x" }; // x标记
var obj2 = { name: "y" }; // y标记
obj1.child = obj2; // y标记
obj2.child = obj1; // x标记
//改变值,没有引用,没有标记
// obj1 = null;
// obj2 = null;