当前位置: 首页 > article >正文

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

文章目录

    • 垃圾回收
      • 垃圾回收原理
      • 常见的垃圾回收方法
        • 1. 标记清除算法(Mark and Sweep)
        • 2. 标记整理算法(Mark and Compact)
        • 3. 复制算法(Copying)
        • 4. 分代回收算法(Generational Garbage Collection)
      • 手动触发垃圾回收
    • js中对象怎么做到弱引用
      • 1. `WeakMap`
        • 基本语法
        • 示例代码
        • 使用场景
      • 2. `WeakSet`
        • 基本语法
        • 示例代码
        • 使用场景
    • 垃圾回收与弱引用之间的关系
      • 弱引用与垃圾回收的关系
        • 强引用与垃圾回收
        • 弱引用与垃圾回收(WeakMap)
      • 应用场景
        • 1. 缓存数据
        • 2. 实现私有属性和方法
        • 3. 跟踪对象状态
      • 弱引用与垃圾回收(WeakSet )
      • 1. `WeakSet` 的基本概念
      • 2. `WeakSet` 与垃圾回收的关系
        • 强引用和弱引用对垃圾回收的影响
        • 垃圾回收时机
      • 3. `WeakSet` 的特性与垃圾回收的关联
      • 4. 示例代码
      • 5. 应用场景

垃圾回收

在 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中对象怎么做到弱引用

在 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.kler.cn/a/530448.html

相关文章:

  • Hive之数据定义DDL
  • 【Block总结】完全注意力Fully Attentional,同时捕捉空间和通道的注意力|即插即用
  • Hutool工具类
  • Elasticsearch的索引生命周期管理
  • AI学习指南HuggingFace篇-Tokenizers 与文本处理
  • 解决Django非ORM模型提示初始化request问题
  • 硕成C语言4
  • 【Conda 和 虚拟环境详细指南】
  • 飞行汽车与人形机器人,无刷外转子电机与无框力矩电机,接小鹏飞行汽车后续
  • Rust 数据类型详解:Scalar 与 Compound 类型
  • Hot100之二分查找
  • 深度卷积神经网络实战无人机视角目标识别
  • (笔记+作业)书生大模型实战营春节卷王班---L1G3000 浦语提示词工程实践
  • MySQL入门 – CRUD基本操作
  • 洛谷 P1130 红牌 C语言
  • 亲和传播聚类算法应用(Affinity Propagation)
  • javaEE-7.网络原理-HTTPS
  • 2.2.1 人眼色觉与色度图
  • 实验十 Servlet(一)
  • C# 操作符重载对象详解
  • DeepSeek的出现对全球GPT产业产生的冲击
  • 【JAVA篇】------ spring aop
  • 【C语言设计模式学习笔记1】面向接口编程/简单工厂模式/多态
  • MATLAB中open函数用法
  • 一文总览OpenAI o1相关的技术:从CoT、Quiet-STaR、Self-Correct、Self-play RL、MCTS等到类o1模型rStar-Math
  • 在GPIO控制器中,配置通用输入,读取IO口电平时,上拉和下拉起到什么作用