一、指令材料
1.定义
JavaScript(JS)的垃圾回收机制是一种自动管理内存的过程,它有助于释放不再使用的内存,以避免内存泄漏和提高程序的性能。
JavaScript的垃圾回收机制是一种自动管理内存的方式,以确保不再被引用的对象可以被垃圾回收,释放内存。
2.分类
2-1. 引用计数算法
引用计数算法通过跟踪每个对象被引用的次数来决定何时回收内存。当一个对象的引用计数为零时,它就会被垃圾回收.
2-2. 循环引用
循环引用是一种特殊情况,其中两个或多个对象互相引用,导致它们的引用计数不会降为零。这时,垃圾回收需要使用更复杂的算法来检测并处理循环引用。
2-3. 标记清除算法
标记清除算法通过标记所有从根对象(通常是全局对象)可达的对象,然后清除未标记的对象来回收内存。
二、 限定条件
JavaScript的垃圾回收机制主要涉及对象的管理,而基本数据类型通常不涉及垃圾回收,因为它们是简单的值,而不是对象。JavaScript的垃圾回收机制更关注于复杂数据类型,如对象和数组。
- 数字(Number): 基本数据类型的数字是不需要垃圾回收的,因为它们只是简单的数值,没有引用其他对象或数据。
let x = 42; // 基本数据类型的数字
- 字符串(String): 基本数据类型的字符串也不需要垃圾回收,因为它们是不可变的,没有内部引用需要跟踪。
let name = "John"; // 基本数据类型的字符串
- 布尔值(Boolean): 基本数据类型的布尔值也不需要垃圾回收,因为它们只表示真或假。
let isLogged = true; // 基本数据类型的布尔值
- 空值(null)和未定义(undefined): 这些特殊的基本数据类型表示缺少值或未定义的值。它们也不需要垃圾回收。
let emptyValue = null; // 空值
let undefinedValue; // 未定义
三、做练习题
1. 引用计数算法
// 把 {name: ‘John’} 代指A
// A 对象被obj1 引用1次,A 引用计数=1次
let obj1 = { name: 'John' };
// A 对象被obj2 引用1次,A 引用计数=2次
let obj2 = obj1; // 解除obj1 的引用对象A, A 引用计数 = 1 次
obj1 = null;
// 解除obj2 的引用对象A, A 引用计数 = 0 次
obj2 = null; // 对象A 没有被任何变量引用,将被垃圾回收机制回收
总结归纳:
- 引用计数是指一个对象的堆内存空间被引用了几次
- 通过=号,给变量赋值对象,引用增加
- 通过=号,给变量赋值为null, 解除对象的引用
2-1. 循环引用
function createCircularReference() {// 把 {} 代指 A, A 被obj1 引用1次, A的引用计数 = 1次let obj1 = {}; // // 把 {} 代指 B, B 被obj1 引用1次, B的引用计数 = 1次let obj2 = {}; // // B 被 obj1.circularRef 引用1次, B的引用计数 = 2次obj1.circularRef = obj2; // A 被 obj2.circularRef 引用1次, A的引用计数 = 2次obj2.circularRef = obj1; // 这里有一个循环引用,即obj1和obj2互相引用
}// 当函数执行完毕后,obj1和obj2都会离开作用域,
// 但由于它们互相引用,它们的引用计数不会降为零,
// 垃圾回收需要检测和处理这种循环引用```
总结归纳:
- 循环引用,引用计数不会降为零
- 循环引用是通过两个对象的属性,相互赋值另外一个对象,实现相互引用
1和2-1对比归纳:
- 大括号中无论是否有值,都会开辟新的内存空间
- 绑定引用和解除引用都使用=号,
2-2. 手动解除引用
你可以通过将循环引用的其中一个对象设置为null来手动解除引用。这将打破循环引用,允许垃圾回收器正确地识别这些对象并释放它们。
// 循环引用
const obj1 = {};
const obj2 = {};
obj1.ref = obj2;
obj2.ref = obj1;// 手动解除引用obj1.ref = null;
obj2.ref = null;
总结归纳:
- 绑定引用和解除引用的属性或对象,要保持一致性
2-3. WeakMap和WeakSet 解除引用
JavaScript提供了WeakMap和WeakSet数据结构,它们允许你存储弱引用(不会阻止垃圾回收的引用)。这些数据结构不会阻止对象被回收,因此可以用于解决循环引用问题。当你不再需要这些引用时,它们会自动被垃圾回收
const obj1 = {};
const obj2 = {};const weakMap = new WeakMap();
weakMap.set(obj1, obj2);
weakMap.set(obj2, obj1);// 当不再需要循环引用时,它们会被自动释放
总结归纳:
- 使用 weakMap方法,内存变成弱引用,不受引用计数的影响,自动被回收站回收。
3. 标记清除算法
标记清除算法通过标记所有从根对象(通常是全局对象)可达的对象,然后清除未标记的对象来回收内存。
// 标记所有能够从根对象访问到的对象,通常包括全局变量、当前调用栈中的变量等。标记的对象会被标记为“活动”
function createUser() {let user = {name: 'Alice',age: 30 };return user;
}
// 遍历:垃圾回收器遍历整个对象图,标记所有与活动对象相互引用的对象,以确保不会因为被引用而被清除。
let userData = createUser();
// 现在userData不再引用对象
userData = null; // 当userData变为null后,活动对象被解除引用
// 垃圾回收会将这个对象createUser()清除
总结归纳:
- 标记全局变量下对象,为活动对象
- 遍历查询出,哪些活动对象被引用,防止被垃圾回收
总结规律:
- 引用计数是指一个对象的堆内存空间被引用了几次
- 通过=号,给变量赋值对象,引用增加
- 通过=号,给变量赋值为null, 解除对象的引用
- 循环引用是通过两个对象的属性,相互赋值另外一个对象,实现相互引用
- 循环引用,引用计数不会降为零
- 手动解除引用,通过把基本数据类型赋值给变量,解除变量和对象的引用关系
- 对象弱引用,使用weakMap和WeakSet方法实现两个对象的弱引用,使用完成后允许垃圾回收
- 标记全局变量下对象,为活动对象
- 遍历查询出,哪些活动对象被引用,防止被垃圾回收
四、建立新学的知识与旧知识之间的关联
1. js的垃圾回收机制和 delete 删除对象的属性
- js的垃圾回收机制,把代码中没有被引用的对象,自动清除该对象所占用的内存空间;delete 删除对象的属性
- 两者之间的区别
- 一个清除未被引用对象的内存空间;一个是删除对象的属性
- 一个自动清除;一个是手动删除
- 两者的本质:都是清除掉不需要的东西,达成某个功能
// {name:'xiao'} 被obj1 引用1次,{name:'xiao'} 的引用计数 = 1
let obj1 = {name:'xiao'}
// 解除 ob1 和 {name:'xiao'} 引用关系, {name:'xiao'}的引用计数 = 0, {name:'xiao'} 将被垃圾回收
obj1 = null
let params = {id: 123,name: 'xiao'phone: '123456789'
}
// 业务需求是,新增时,删除id
if (state === 'add'){delete params.id
}
2. 引用计数算法(暂时想不到与那个旧知识关联,日后补充)
3. 标记清除算法(暂时想不到与那个旧知识关联,日后补充)
五、 转换表述
1. js的垃圾回收机制
垃圾回收机制,就是我们平时去吃火锅时,每一盘菜就是就是一个正在被使用的内存,当菜被吃完后,服务员会把空盘子自动拿走,以保证桌面整洁和提高用户体验。
2. 引用计数算法
引用计数算法就像我们吃完火锅,一包卫生纸盒,给每个人都发一张,直到卫生纸都发完了,只剩下空纸盒,它就会被垃圾回收。引用计数的本质是,该物品(或对象)对某人或事物,还有没有它的价值。
3. 循环引用
循环引用就是两个正在热恋的年轻人,两个人相互吸引,都离不开对方,脑海中无时无刻在想着对方,所以引用计数永远不会为零,直到他们分手时,他们之间的引用计数才会变成0
4. 标记清除算法
标记清除算法就是书桌上有很多东西,比如零食、玩具、书本、笔,然后现在妈妈让你写作业,把无关的东西收拾起来,零食、玩具就会被收拾起来(垃圾回收)。
标记清除算法的本质,把没有使用的东西清除掉。