垃圾回收之弱引用+实例说明+weakSet+weakMap

devtools/2025/2/3 20:50:14/

文章目录

    • 垃圾回收
      • 垃圾回收原理
      • 常见的垃圾回收方法
        • 1. 标记清除算法(Mark and Sweep)
        • 2. 标记整理算法(Mark and Compact)
        • 3. 复制算法(Copying)
        • 4. 分代回收算法(Generational Garbage Collection)
      • 手动触发垃圾回收
    • js中对象怎么做到弱引用
      • 1. `WeakMap`
        • 基本语法
        • 示例代码
        • 使用场景
      • 2. `WeakSet`
        • 基本语法
        • 示例代码
        • 使用场景
    • 垃圾回收与弱引用之间的关系

垃圾回收

在 JavaScript 中,垃圾回收(Garbage Collection,简称 GC)是自动管理内存的机制,它负责回收不再被程序使用的内存空间,以避免内存泄漏,提高内存使用效率。下面详细介绍 JavaScript 垃圾回收的原理和常见方法。

垃圾回收原理

JavaScript 是一种使用自动内存管理的语言,其垃圾回收的核心原理基于可达性分析。即判断一个对象是否可以被程序访问到,如果一个对象无法通过任何可达的引用路径被访问,那么这个对象就被认为是“垃圾”,可以被回收。

常见的垃圾回收方法

1. 标记清除算法(Mark and Sweep)

这是最基础也是最常见的垃圾回收算法,现代浏览器大多采用这种算法的改进版本。其工作过程分为两个阶段:

  • 标记阶段垃圾回收器从根对象(如全局对象 window)开始,遍历所有可达对象,并为它们标记。根对象是指那些在程序中可以直接访问的对象,例如全局变量、函数调用栈中的变量等。
  • 清除阶段垃圾回收器遍历整个内存空间,将未被标记的对象视为垃圾,并释放它们所占用的内存空间。

示例解释

// 创建一个对象
let obj1 = { name: 'object1' };
let obj2 = { name: 'object2' };// obj1 引用 obj2
obj1.ref = obj2;// 移除对 obj2 的直接引用
obj2 = null;// 此时,obj2 仍然可以通过 obj1.ref 访问到,所以不会被标记为垃圾// 移除对 obj1 的引用
obj1 = null;// 现在 obj1 和 obj2 都无法从根对象访问到,在下一次垃圾回收时,它们将被标记并清除
2. 标记整理算法(Mark and Compact)

标记整理算法是标记清除算法的改进版本,它解决了标记清除算法可能导致的内存碎片化问题。其工作过程分为三个阶段:

  • 标记阶段:与标记清除算法相同,从根对象开始遍历,标记所有可达对象。
  • 整理阶段:将所有存活的对象向内存的一端移动,使它们连续存储,从而消除内存碎片。
  • 清除阶段:释放所有未被标记的对象所占用的内存空间。
3. 复制算法(Copying)

复制算法将内存空间分为两个相等的区域:一个是使用区(From Space),另一个是空闲区(To Space)。其工作过程如下:

  • 当程序运行时,所有对象都分配在使用区。
  • 当使用区内存不足时,垃圾回收器开始工作。它从根对象开始遍历,将所有存活的对象复制到空闲区。
  • 复制完成后,交换使用区和空闲区的角色,原来的使用区变为空闲区,原来的空闲区变为使用区。

优点:复制算法的效率较高,因为它只需要移动存活的对象,并且不会产生内存碎片。
缺点:需要额外的内存空间,因为要将内存分为两个区域,实际可用的内存只有一半。

4. 分代回收算法(Generational Garbage Collection)

分代回收算法基于一个经验观察:大多数对象的生命周期都很短,而少数对象的生命周期很长。因此,该算法将对象分为不同的代(Generation),不同代采用不同的垃圾回收策略。

  • 新生代(Young Generation):新创建的对象通常被分配到新生代。新生代使用复制算法进行垃圾回收,因为新生代中的对象大多很快就会死亡,复制算法可以高效地处理这些对象。
  • 老生代(Old Generation):经过多次垃圾回收仍然存活的对象会被晋升到老生代。老生代使用标记清除或标记整理算法进行垃圾回收,因为老生代中的对象生命周期较长,复制算法的效率较低。

手动触发垃圾回收

在 JavaScript 中,通常不建议手动触发垃圾回收,因为现代浏览器和 JavaScript 引擎会自动管理垃圾回收的时机,以优化性能。不过,在某些环境中(如 Node.js),可以使用以下方法手动触发垃圾回收

if (global.gc) {global.gc();
}

需要注意的是,手动触发垃圾回收可能会影响程序的性能,应该谨慎使用。

js_66">js中对象怎么做到弱引用

在 JavaScript 里,ES6 引入了 WeakMapWeakSet 这两种数据结构来实现对象的弱引用。下面分别介绍它们的使用方式和特点。

1. WeakMap

WeakMap 是一种键值对集合,它的键必须是对象,并且这些对象是弱引用的。当对象的其他强引用都被移除后,WeakMap 中的键对象会被垃圾回收,对应的键值对也会自动从 WeakMap 中移除。

基本语法
const weakMap = new WeakMap();
示例代码
// 创建一个对象
const obj1 = {};
const obj2 = {};// 创建一个 WeakMap
const weakMap = new WeakMap();// 向 WeakMap 中添加键值对
weakMap.set(obj1, 'value for obj1');
weakMap.set(obj2, 'value for obj2');// 获取值
console.log(weakMap.get(obj1)); // 输出: 'value for obj1'// 检查某个键是否存在
console.log(weakMap.has(obj2)); // 输出: true// 删除键值对
weakMap.delete(obj1);
console.log(weakMap.has(obj1)); // 输出: false// 当对象的其他强引用被移除后,WeakMap 中的键值对会自动被清理
let key = { name: 'temp' };
weakMap.set(key, 'temporary value');
key = null; // 移除对对象的强引用
// 一段时间后(垃圾回收执行时),该键值对会从 WeakMap 中消失
使用场景
  • 缓存数据:当你需要为对象关联一些额外的数据,并且不希望这些数据阻止对象被垃圾回收时,可以使用 WeakMap
  • 私有数据存储:可以使用 WeakMap 来模拟对象的私有属性。

2. WeakSet

WeakSet 是一种只存储对象的集合,这些对象也是弱引用的。与 WeakMap 类似,当对象的其他强引用被移除后,对象会从 WeakSet 中自动移除。

基本语法
const weakSet = new WeakSet();
示例代码
// 创建对象
const objA = {};
const objB = {};// 创建一个 WeakSet
const weakSet = new WeakSet();// 向 WeakSet 中添加对象
weakSet.add(objA);
weakSet.add(objB);// 检查对象是否存在于 WeakSet 中
console.log(weakSet.has(objA)); // 输出: true// 删除对象
weakSet.delete(objB);
console.log(weakSet.has(objB)); // 输出: false// 当对象的其他强引用被移除后,WeakSet 中的对象会自动被清理
let item = { id: 1 };
weakSet.add(item);
item = null; // 移除对对象的强引用
// 一段时间后(垃圾回收执行时),该对象会从 WeakSet 中消失
使用场景
  • 跟踪对象状态:可以使用 WeakSet 来跟踪某些对象是否处于某个特定状态,而不会影响对象的生命周期。

需要注意的是,WeakMapWeakSet 都没有迭代器,不能使用 for...of 循环,也没有 size 属性,因为它们的主要目的是提供弱引用功能,避免影响对象的垃圾回收

垃圾回收与弱引用之间的关系

弱引用与垃圾回收的关系

在 JavaScript 中,垃圾回收(Garbage Collection,简称 GC)是自动管理内存的机制,其核心原则是回收不再被程序使用的内存空间,以避免内存泄漏。而弱引用是一种特殊的引用方式,它不会阻止对象被垃圾回收,二者存在紧密的联系:

强引用与垃圾回收

在正常情况下,当一个对象被其他变量或数据结构引用时,这种引用是强引用。只要存在强引用指向一个对象,该对象就不会被垃圾回收机制回收。例如:

const obj = { name: 'example' };
// 这里 obj 对对象 { name: 'example' } 是强引用
// 只要 obj 存在,这个对象就不会被垃圾回收
弱引用与垃圾回收(WeakMap)

JavaScript 中的 WeakMapWeakSet 实现了弱引用。当对象仅被 WeakMapWeakSet 引用时,这些引用不会阻止对象被垃圾回收。一旦对象的所有强引用都被移除,垃圾回收机制会在合适的时机回收该对象,同时 WeakMapWeakSet 中对应的引用也会自动消失。例如:

const weakMap = new WeakMap();
let key = { id: 1 };
weakMap.set(key, 'value');
// 此时 key 对对象 { id: 1 } 是强引用,weakMap 对它是弱引用key = null; 
// 移除了对对象 { id: 1 } 的强引用
// 当垃圾回收执行时,对象 { id: 1 } 会被回收,weakMap 中对应的键值对也会自动移除

应用场景

1. 缓存数据

在开发中,有时需要为某些对象缓存一些额外的数据,但又不希望缓存的数据阻止对象被垃圾回收。使用 WeakMap 可以很好地实现这一需求。

// 假设我们有一个函数需要为对象缓存一些计算结果
const cache = new WeakMap();function calculateAndCache(obj) {if (cache.has(obj)) {return cache.get(obj);}// 进行一些复杂的计算const result = /* 复杂计算逻辑 */ obj.id * 2;cache.set(obj, result);return result;
}let myObject = { id: 5 };
const result = calculateAndCache(myObject);
console.log(result);myObject = null; 
// 当 myObject 的强引用被移除后,它和对应的缓存数据都会被垃圾回收
2. 实现私有属性和方法

WeakMap 可以用来模拟对象的私有属性和方法,因为外部无法直接访问 WeakMap 中的数据,并且不会影响对象的生命周期。

const privateData = new WeakMap();class MyClass {constructor() {privateData.set(this, {secret: 'This is a private value'});}getSecret() {return privateData.get(this).secret;}
}const instance = new MyClass();
console.log(instance.getSecret()); instance = null; 
// 当 instance 的强引用被移除后,对象和对应的私有数据都会被垃圾回收
3. 跟踪对象状态

WeakSet 可以用于跟踪某些对象是否处于某个特定状态,而不会影响对象的生命周期。例如,在一个游戏中,跟踪哪些角色已经被标记为死亡。

const deadCharacters = new WeakSet();class Character {constructor(name) {this.name = name;}die() {deadCharacters.add(this);}isDead() {return deadCharacters.has(this);}
}const character1 = new Character('Hero');
character1.die();
console.log(character1.isDead()); character1 = null; 
// 当 character1 的强引用被移除后,它会从 deadCharacters 中自动移除

通过使用弱引用,可以更灵活地管理内存,避免因不必要的引用导致的内存泄漏问题。

弱引用与垃圾回收(WeakSet )

1. WeakSet 的基本概念

WeakSet 是 JavaScript 中的一种数据结构,它是一个集合,只能存储对象,并且这些对象是弱引用的。这意味着 WeakSet 中的对象不会阻止垃圾回收机制对它们的回收。

2. WeakSet垃圾回收的关系

强引用和弱引用对垃圾回收的影响
  • 强引用:当一个对象被其他变量或数据结构以常规方式引用时,这种引用是强引用。只要存在强引用指向一个对象,该对象就不会被垃圾回收。例如:
const obj = { key: 'value' };
// 这里 obj 对 { key: 'value' } 是强引用,只要 obj 存在,这个对象就不会被回收
  • 弱引用WeakSet 中的对象是弱引用。如果一个对象仅被 WeakSet 引用,而没有其他强引用指向它,那么该对象就可以被垃圾回收。当对象被垃圾回收后,它会自动从 WeakSet 中移除。例如:
const weakSet = new WeakSet();
let obj = { key: 'value' };
weakSet.add(obj);
// 此时 obj 对 { key: 'value' } 是强引用,weakSet 对它是弱引用obj = null; 
// 移除了对对象 { key: 'value' } 的强引用
// 当垃圾回收执行时,对象 { key: 'value' } 会被回收,并且会自动从 weakSet 中移除
垃圾回收时机

JavaScript 的垃圾回收机制是自动且不可预测的,它会在内存达到一定阈值或者空闲时触发。因此,我们无法精确知道对象何时会从 WeakSet 中被移除,但可以确定的是,一旦对象的所有强引用被移除,它最终会被回收,并且会从 WeakSet 中消失。

3. WeakSet 的特性与垃圾回收的关联

  • 不能遍历WeakSet 没有 forEach 方法,也不能使用 for...of 循环,因为其成员随时可能被垃圾回收,遍历可能会导致结果不一致。
  • 没有 size 属性:由于 WeakSet 中的对象可能随时被回收,size 属性的值会不断变化,因此 WeakSet 没有 size 属性。

4. 示例代码

// 创建一个 WeakSet
const weakSet = new WeakSet();// 创建对象
const obj1 = { id: 1 };
const obj2 = { id: 2 };// 将对象添加到 WeakSet 中
weakSet.add(obj1);
weakSet.add(obj2);// 检查对象是否存在于 WeakSet 中
console.log(weakSet.has(obj1)); // 输出: true// 移除对 obj1 的强引用
obj1 = null;// 此时垃圾回收机制可能还未执行,obj1 可能还在 WeakSet 中
// 当垃圾回收执行后,obj1 会被回收,并且会自动从 WeakSet 中移除// 手动触发垃圾回收(在某些环境中可能有效)
if (global.gc) {global.gc();
}// 再次检查 obj1 是否存在于 WeakSet 中
console.log(weakSet.has(obj1)); // 输出: false(假设垃圾回收已执行)

5. 应用场景

  • 跟踪对象状态:可以使用 WeakSet 来跟踪某些对象是否处于某个特定状态,而不会影响对象的生命周期。例如,在一个图形库中,跟踪哪些图形元素已经被标记为隐藏。
const hiddenElements = new WeakSet();class GraphicElement {constructor(id) {this.id = id;}hide() {hiddenElements.add(this);}isHidden() {return hiddenElements.has(this);}
}const element = new GraphicElement(1);
element.hide();
console.log(element.isHidden()); element = null; 
// 当 element 的强引用被移除后,它会从 hiddenElements 中自动移除

通过使用 WeakSet,可以避免因不必要的引用导致的内存泄漏问题,让对象在不再被使用时能够及时被垃圾回收


http://www.ppmy.cn/devtools/155826.html

相关文章

Python爬虫:requests模块深入及案例

* [案例二:输入单词获取百度翻译的结果](about:blank#_40)* [案例三:获取豆瓣电影的评分前几名的电影信息](about:blank#_87)* [案例四:通过在药监局网站中的企业id值获取企业信息](about:blank#id_121)案例一:获取CSDN关键…

菜鸟之路Day08一一集合进阶(一)

菜鸟之路Day08一一集合进阶(一) 作者:blue 时间:2025.1.26 文章目录 菜鸟之路Day08一一集合进阶(一)1.五道经典算法题1.1自定义排序1.2不死神兔1.3猴子吃桃子1.4爬楼梯1.5爬楼梯plus 2.单列集合2.1单列集合体系结构2.2Collection2.2.1Collection的常用…

01学习预热篇(D6_正式踏入JVM深入学习前的铺垫)

目录 学习前言 一、虚拟机的结构 1. Java虚拟机参数设置 2. java 堆 3. 出入栈 4. 局部变量表 1> 局部变量的剖析 2> 局部变量的回收 5. 操作数栈 1> 常量入栈指令 2> 局部变量值转载到栈中指令 3> 将栈顶值保存到局部变量中指令 6. 帧数据区 7. 栈…

vim多文件操作如何同屏开多个文件

[rootxxx ~]# vimdiff aa.txt bb.txt cc.txt #带颜色比较的纵向排列打开的同屏多文件操作 示例: [rootxxx ~]# vimdiff -o aa.txt bb.txt cc.txt #带颜色比较的横向排列打开的同屏多文件操作 示例: [rootxxx ~]# vim -O aa.txt bb.txt c…

Kafka 压缩算法详细介绍

文章目录 一 、Kafka 压缩算法概述二、Kafka 压缩的作用2.1 降低网络带宽消耗2.2 提高 Kafka 生产者和消费者吞吐量2.3 减少 Kafka 磁盘存储占用2.4 减少 Kafka Broker 负载2.5 降低跨数据中心同步成本 三、Kafka 压缩的原理3.1 Kafka 压缩的基本原理3.2. Kafka 压缩的工作流程…

【Rust自学】18.3. 模式(匹配)的语法

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 18.3.1. 匹配字面值 模式可以直接匹配字面值。看个例子: let x 1;match x {1…

基于UKF-IMM无迹卡尔曼滤波与交互式多模型的轨迹跟踪算法matlab仿真,对比EKF-IMM和UKF

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于UKF-IMM无迹卡尔曼滤波与交互式多模型的轨迹跟踪算法matlab仿真,对比EKF-IMM和UKF。 2.测试软件版本以及运行结果展示 MATLAB2022A版本运行 3.核心程序 .…

CodeGPT使用本地部署DeepSeek Coder

目前NV和github都托管了DeepSeek,生成Key后可以很方便的用CodeGPT接入。CodeGPT有三种方式使用AI,分别时Agents,Local LLMs(本地部署AI大模型),LLMs Cloud Model(云端大模型,从你自己…