首页 > 其他分享 >js Weakset和Set 对比,弱引用和强引用

js Weakset和Set 对比,弱引用和强引用

时间:2025-01-06 22:45:29浏览次数:1  
标签:obj2 对象 回收 Set 引用 Weakset WeakSet

SetWeakSet 都保存对对象(如 obj1)的引用,但它们处理这些引用的方式不同,这直接影响到垃圾回收的行为。

强引用 vs. 弱引用

  • 强引用:当一个对象被 Set 引用时,Set 持有的是对该对象的强引用。这意味着只要 Set 存在并且包含这个对象,JavaScript 的垃圾回收机制就不会回收这个对象,即使没有其他的变量引用它。因此,Set 中的对象会一直存在,直到你显式地从 Set 中删除它或者清空 Set

  • 弱引用WeakSet 持有的是对象的弱引用。如果一个对象只被 WeakSet 引用而没有其他强引用,那么这个对象可能会在任何时候被垃圾回收。WeakSet 不会阻止垃圾回收器回收这些对象,因此一旦对象不再有强引用,它就可能被移除并回收。

示例

让我们通过一个具体的例子来说明这两种行为:

// 创建两个对象
const obj1 = { name: 'Object 1' };
const obj2 = { name: 'Object 2' };

// 创建 Set 和 WeakSet 实例
const mySet = new Set();
const myWeakSet = new WeakSet();

// 将 obj1 和 obj2 分别添加到 Set 和 WeakSet 中
mySet.add(obj1);
myWeakSet.add(obj2);

// 清除 obj1 和 obj2 的所有外部引用
obj1 = null;
obj2 = null;

// 在这里,你可以使用浏览器的开发者工具或 Node.js 环境中的 gc() 函数来尝试触发垃圾回收。
if (global.gc) {
    global.gc(); // 手动触发垃圾回收(仅在某些环境中有效)
}

// 检查垃圾回收后的状态
setTimeout(() => {
    console.log('After attempting garbage collection:');
    
    // 对于 Set,obj1 仍然存在,因为它持有强引用
    console.log('Set size:', mySet.size); // 输出 1 或 0,取决于垃圾回收是否发生
    for (let item of mySet) {
        console.log('Set contains:', item.name); // 如果 obj1 还未被回收,输出 "Object 1"
    }

    // 对于 WeakSet,obj2 可能已经被垃圾回收,因为它只持有弱引用
    console.log('WeakSet has obj2:', myWeakSet.has(obj2)); // 输出 false,因为 obj2 已经被设置为 null
}, 0);

解释

  • Set 的行为

    • obj1 被添加到 Set 中后,Set 持有对 obj1 的强引用。
    • 即使我们将 obj1 设置为 nullSet 仍然持有对原始对象的强引用,因此这个对象不会被垃圾回收。
    • 如果我们遍历 Set,我们仍然可以看到 obj1 的内容(前提是垃圾回收尚未发生)。
  • WeakSet 的行为

    • obj2 被添加到 WeakSet 中后,WeakSet 持有对 obj2 的弱引用。
    • 当我们将 obj2 设置为 null 时,obj2 没有其他强引用,因此它可以被垃圾回收。
    • 垃圾回收发生后,WeakSet 中的 obj2 会被自动移除,myWeakSet.has(obj2) 会返回 false

关键点

  • Set:持有强引用,防止对象被垃圾回收,直到你显式地从 Set 中删除对象或清空 Set
  • WeakSet:持有弱引用,允许对象在没有其他强引用时被垃圾回收,WeakSet 会自动移除这些对象。

总结

  • Set 适合用于需要持久化存储对象的场景,确保对象不会被意外回收。
  • WeakSet 适合用于临时关联数据或实现某种形式的私有化机制,避免内存泄漏,尤其是在你不希望对象长时间存在于内存中的情况下。

通过这种方式,你可以根据具体的需求选择合适的集合类型,以优化内存管理和数据结构的设计。

WeakSet不会阻止垃圾回收对象,只要这个对象没被任何地方强引用了,垃圾回收就会回收对象,不会去管WeakSet是否还用着这个对象。

标签:obj2,对象,回收,Set,引用,Weakset,WeakSet
From: https://www.cnblogs.com/jocongmin/p/18656444

相关文章

  • vue3 useTemplateRef()返回null
    新版写法(Vue3.5以后)在Vue3.5开始,引入了useTemplateRef(),文档中是这么说的:当ref在v-for内部使用时,相应的ref应包含一个Array值,该值将在mount之后填充元素:<scriptsetup>import{ref,useTemplateRef,onMounted}from'vue'constlist=ref([/*...*/])......
  • MapContext.setBoundary
    MapContext.setBoundary(Objectobject)基础库2.22.0开始支持,低版本需做兼容处理。以Promise风格调用:不支持小程序插件:支持相关文档:map功能描述限制地图的显示范围。此接口同时会限制地图的最小缩放整数级别。参数Objectobject属性类型默认值必填......
  • MapContext.setLocMarkerIcon
    MapContext.setLocMarkerIcon(Objectobject)基础库2.16.0开始支持,低版本需做兼容处理。以Promise风格调用:不支持小程序插件:支持微信鸿蒙OS版:支持相关文档:map功能描述设置定位点图标,支持网络路径、本地路径、代码包路径参数Objectobject属性类型......
  • MapContext.setCenterOffset
    MapContext.setCenterOffset(Objectobject)基础库2.10.0开始支持,低版本需做兼容处理。以Promise风格调用:不支持小程序插件:支持微信鸿蒙OS版:支持相关文档:map功能描述设置地图中心点偏移,向后向下为增长,屏幕比例范围(0.25~0.75),默认偏移为[0.5,0.5]参数Ob......
  • 6.4 Using tokens with references 将令牌与引用一起使用
    https://lalrpop.github.io/lalrpop/lexer_tutorial/004_token_references.htmlWhenusingacustomlexer,youmightwanttokenstoholdreferencestotheoriginalinput.Thisallowstousereferencestotheinputwhenthegrammarcanhavearbitrarysymbolssu......
  • Redis数据库笔记——ZSet的底层实现(跳表)
    大家好,这里是GoodNote,关注公主号:Goodnote,专栏文章私信限时Free。本文详细介绍ZSet数据类型中跳表的底层实现,包括基本特点和常用操作。文章目录ZSet(有序集合)概述基本特点底层实现Skiplist跳表概述结构跳表的基本操作1.查找操作:`Search`2.插入操作:`Insert`3.删......
  • 软件缺少NetSetupEngine.dll文件及错误提示问题
    在大部分情况下出现我们运行或安装软件,游戏出现提示丢失某些DLL文件或OCX文件的原因可能是原始安装包文件不完整造成,原因可能是某些系统防护软件将重要的DLL文件识别为可疑,阻止并放入了隔离单里,还有一些常见的DLL文件缺少是因为系统没有安装齐全的微软运行库,还有部分情况是因为......
  • `QualitySettings.asyncUploadPersistentBuffer
    在Unity中,`QualitySettings.asyncUploadPersistentBuffer`是一个静态属性,它控制着纹理上传到GPU的异步方式。当启用时(设置为`true`),Unity会创建一个持久的缓冲区用于异步上传纹理数据到GPU,这可以提高性能,尤其是在有大量纹理需要加载或更新的情况下。具体来说,当使用异步纹......
  • 0.STL,Vector,Set基础
    STL、Vector、Set基础1.STLc++提供了一套标准模板库——STL包含三大组件:容器:存储数据的数据结构,类模板的实例,常见的有vector,set,string,map算法:用于操作容器内数据的函数模板,可以应用于任何兼容的容器,常见的有sort,find,copy迭代器:用于遍历容器元素的,像指针的对象,提......
  • Mybatis 映射文件中,如果 A 标签通过 include 引用了 B 标签的内容,请问,B 标签能否定义
    在MyBatis的映射文件中,如果A标签通过 <include> 引用了B标签的内容,那么B标签必须定义在A标签的前面。这是因为MyBatis在解析XML文件时是按顺序进行的,它需要在解析到 <include> 标签时已经知道被引用的内容。示例假设我们有一个映射文件 UserMapper.xml,其......