【问题标题】:Is it possible to create a "weak reference" in JavaScript?是否可以在 JavaScript 中创建“弱引用”?
【发布时间】:2010-09-20 23:16:38
【问题描述】:

在 JavaScript 中有什么方法可以创建对另一个对象的“弱引用”? Here is the wiki page describing what a weak reference is. Here is another article that describes them in Java. 谁能想到在 JavaScript 中实现这种行为的方法?

【问题讨论】:

标签: javascript weak-references


【解决方案1】:

更新:自 2020 年 7 月以来,一些实现(Chrome、Edge、Firefox 和 Node.js)已支持 WeakRefs,如 WeakRefs proposal 中定义的那样,这是一个“第 3 阶段草案” 2020 年 12 月 16 日。

JavaScript 中没有对弱引用的语言支持。您可以使用手动引用计数自己滚动,但不是特别顺利。你不能创建一个代理包装对象,因为在 JavaScript 中对象永远不知道它们什么时候会被垃圾回收。

因此,您的“弱引用”成为简单查找中的键(例如整数),具有添加引用和删除引用方法,当不再有手动跟踪的引用时,可以删除条目,留下将来对该键进行查找以返回 null。

这并不是真正的弱引用,但它可以解决一些相同的问题。当 DOM 节点或事件处理程序与与其关联的对象(例如闭包)之间存在引用循环时,通常在复杂的 Web 应用程序中执行此操作,以防止浏览器(通常是 IE,尤其是旧版本)发生内存泄漏。在这些情况下,甚至可能不需要完整的引用计数方案。

【讨论】:

【解决方案2】:

在NodeJS上运行JS时,可以考虑https://github.com/TooTallNate/node-weak

【讨论】:

    【解决方案3】:

    更新:2019 年 9 月

    目前还不能使用弱引用,但很可能很快就会成为可能,因为 JavaScript 中的 WeakRefs 正在进行中。详情如下。

    提案

    提案现在处于第 3 阶段,这意味着它具有完整的specification,并且进一步完善需要来自实施和用户的反馈。

    WeakRef 提案包含两个主要的新功能:

    • 使用 WeakRef 类创建对对象的弱引用
    • 在对象被垃圾回收后运行用户定义的终结器,使用 FinalizationGroup 类

    用例

    弱引用的主要用途是实现包含大对象的缓存或映射,其中不希望大对象仅仅因为它出现在缓存或映射中而保持活动状态。

    完成是在程序执行无法访问的对象之后执行代码以进行清理。用户定义的终结器启用了几个新的用例,并且可以在管理垃圾收集器不知道的资源时帮助防止内存泄漏。

    来源和延伸阅读

    https://github.com/tc39/proposal-weakrefs
    https://v8.dev/features/weak-references

    【讨论】:

    【解决方案4】:

    2021 年更新

    WeakRef 现在在 Chrome、Edge 和 Firefox 中实现。仍在等待 Safari 和其他一些坚持。

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef

    2021 年 5 月更新 它现在可以在 Safari 上使用,因此可以在所有主要浏览器上使用。见上文。

    【讨论】:

      【解决方案5】:

      仅供参考; JavaScript 没有,但 ActionScript 3(也是 ECMAScript)有。查看constructor parameter for Dictionary

      【讨论】:

        【解决方案6】:

        他们终于来了。尚未在浏览器中实现,但很快就会实现。

        https://v8.dev/features/weak-references

        【讨论】:

          【解决方案7】:

          真正的弱引用,不,还没有(但浏览器制造商正在研究这个主题)。但这里有一个关于如何模拟弱引用的想法。

          您可以构建一个缓存来驱动您的对象。存储对象时,缓存会预测该对象将占用多少内存。对于某些项目,例如存储图像,这很容易解决。对于其他人来说,这将更加困难。

          当你需要一个对象时,你就向缓存请求它。如果缓存有对象,则返回。如果不存在,则生成、存储并返回该项目。

          当预测的内存总量达到一定水平时,通过缓存删除项来模拟弱引用。它将根据检索的频率预测哪些物品使用最少,并根据它们被取出的时间加权。如果创建项目的代码作为闭包传递到缓存中,则还可以添加“计算”成本。这将允许缓存保留构建或生成非常昂贵的项目。

          删除算法是关键,因为如果你弄错了,那么你最终可能会删除最受欢迎的项目。这会导致糟糕的性能。

          只要缓存是唯一对存储的对象具有永久引用的对象,那么上述系统应该可以很好地替代真正的弱引用。

          【讨论】:

          • 你说的大部分内容不是与weakrefs无关吗?
          • @JL235 -- 弱引用的重要用途不是用于缓存,而是用于事件处理程序。我有一些对象,虽然它存在,但应该观察其他一些事件——但我不希望它在通知列表中的事实构成 GC 的引用。
          • 弱引用与缓存无关。弱引用意味着您想要跟踪某些内容,但如果没有对被跟踪对象的剩余引用,则允许将其删除。
          • 显然有一个用例是使用弱引用构建缓存以实现自动过期。
          • 缓存是传统上弱引用的首要原因。事件处理程序 DOM 只是一些 IE 浏览器错误的东西。
          【解决方案8】:

          使用缓存机制来模拟弱引用,正如JL235 建议的above,是合理的。如果弱引用本来就存在,你会观察到这样的行为:

          this.val = {};
          this.ref = new WeakReference(this.val);
          ...
          this.ref.get(); // always returns val
          ...
          this.val = null; // no more references
          ...
          this.ref.get(); // may still return val, depending on already gc'd or not
          

          而您会观察到缓存:

          this.val = {};
          this.key = cache.put(this.val);
          ...
          cache.get(this.key); // returns val, until evicted by other cache puts
          ...
          this.val = null; // no more references
          ...
          cache.get(this.key); // returns val, until evicted by other cache puts
          

          作为引用的持有者,你不应该对它何时引用一个值做出任何假设,这与使用缓存没有什么不同

          【讨论】:

            【解决方案9】:

            EcmaScript 6 (ES Harmony) 有一个 WeakMap 对象。现代浏览器中的浏览器支持是pretty good(最近 3 个版本的 Firefox、chrome 甚至即将推出的 IE 版本都支持它)。

            【讨论】:

            • 这不完全一样。 WeakMap 不会给对象提供弱引用——在 WeakMap 中弱引用的不是 values,而是 keys。映射中存在弱引用这一事实只是一种内存泄漏预防机制,否则用户无法观察到。
            • 你说得对,关键是弱,而不是值。但是使用弱引用的全部目的是允许对被引用对象进行垃圾回收。 OP 发布了两个链接,其中第二个是关于向无法扩展的对象添加 id,实际上它建议使用 Wea​​kHashMap,Java 等效于 JavaScript 的 WeakMap。
            • 祝你好运,使用 Wea​​kMap 实现弱引用,因为 weakmap.get(new String('any possible key that has ever existed or ever will exist'))始终undefined没有有用。投反对票!
            【解决方案10】:

            http://www.jibbering.com/faq/faq_notes/closures.html

            ECMAScript 使用自动垃圾收集。规范没有定义细节,将其留给实现者进行整理,并且已知一些实现对其垃圾收集操作给予非常低的优先级。但是一般的想法是,如果一个对象变得不可引用(通过没有剩余的对它的引用可供执行代码访问),它就可以用于垃圾收集,并且在将来的某个时候将被销毁,并且它正在消耗的任何资源都被释放并返回到系统重复使用。

            退出执行上下文时通常会出现这种情况。作用域链结构、Activation/Variable 对象和在执行上下文中创建的任何对象(包括函数对象)将不再可访问,因此可用于垃圾回收。

            意思是没有弱的只有那些不再可用的。

            【讨论】:

            • 避免引用循环并不是使用弱引用的唯一原因。它们对于对象实例池/缓存等非常方便。
            • WeakReference 的定义不是问题所在。也同意上面的评论。
            猜你喜欢
            • 2019-01-27
            • 1970-01-01
            • 1970-01-01
            • 2011-03-09
            • 1970-01-01
            • 1970-01-01
            • 2015-06-08
            • 2012-01-16
            • 1970-01-01
            相关资源
            最近更新 更多