【问题标题】:JavaScript: confusion about WeakSet and its effects on garbage collectionJavaScript:关于 WeakSet 及其对垃圾收集的影响的困惑
【发布时间】:2021-04-19 05:06:11
【问题描述】:

我一直在研究 leetcode,遇到了这个问题https://leetcode.com/problems/intersection-of-two-linked-lists/,它要求你找到两个 LinkedList 的交集。一个解决方案(不是我所知道的最好的)是使用散列集来跟踪第一个链表,同时遍历它,然后遍历第二个链表。当我们发现有一个重复节点时,那就是交叉点。

比如E就是路口

A -> B
       \
         E -> F       
       /    
C -> D

我解决的方法是使用WeakSet作为哈希集来存储第一个链表的引用。

这里是代码

var getIntersectionNode = function(headA, headB) {
    let hashSet = new WeakSet()

    while(headA){
        hashSet.add(headA)
        headA = headA.next
    }
    while(headB){
        if(hashSet.has(headB)) return headB
        headB = headB.next
    }
    return null
};

我的问题是,因为WeakSet 有这个很好的特性——当没有其他对存储在 WeakSet 中的对象的引用时,这些对象可以被垃圾回收。如果我们回到这里的示例,当我们遍历A -> B -> E -> F 时,我们将每个节点都添加到哈希集中,但我们不会保留每个节点的引用,即headA = headA.next。这意味着在我将一个节点添加到哈希集中并前进到下一个节点后,对前一个节点的引用消失了,那么它应该从哈希集中进行垃圾收集对吗?那么解决方案怎么会通过呢?

例如,当我们在A时,我们将A存储到哈希集中,然后我们前进到B,现在没有办法引用回A,用WeakSet它应该被垃圾收集。但很明显,如果是这种情况,解决方案就行不通了。有人能指出我的理解哪里错了吗?

【问题讨论】:

  • 那么应该是从哈希集中收集垃圾吧?那解决方案怎么会通过?”你为什么相信为你提供链接列表的代码然后检查您的解决方案本身是否保留对链接列表的引用?

标签: javascript algorithm linked-list


【解决方案1】:

这里有几个问题:

  • 从调用者传递到getIntersectionNode 的原始对象仍然存在至少直到函数完成。如果你这样做了

    someFn({ foo: 'bar' })
    

    在同步 JS 处理完成之前,对象不会被垃圾回收; GC 只在 JS 空闲时运行,即使这样,它也经常需要几秒钟。如果您将一个元素添加到 WeakSet,并且您以某种方式能够观察到由于不再有对它的任何引用而将它从其中删除的确切时间,这将需要一些时间。

  • 即便如此,即使不可引用的对象被立即 GC,在这种情况下,所需要的只是 one 交集节点保持可引用。如果存在交叉点,则该交叉点节点将是某处headA 的子节点,并且该节点也将存在于嵌套在headB 中的某处;即使在遍历headA 之后,在headB 中仍然存在对它的引用。

除非您的脚本执行异步任务(例如等待用户输入或setTimeout),否则在 Set 上使用 Wea​​kSet(或在 Map 上使用 Wea​​kMap)没有任何好处,因为垃圾收集器不会及时运行以使其发挥作用。

【讨论】:

  • 我明白了。谢谢回复。这是否意味着在这种特殊情况下不需要更喜欢WeakSet 而不是Set?我测试了两者,leetcode说在内存使用方面似乎没有区别?我想知道即使我在函数中使用Set,一旦函数返回并且没有关闭该函数的局部变量的闭包,Set 将被垃圾收集,因为一旦函数返回,它本身就不再可访问,所以这里真的不用WeakSet了吗?
  • 确实——因为这里没有什么是异步的,不如使用一个普通的 Set。
  • 好的。只是想仔细检查一下我的理解是否正确:所以如果我们有一个函数function foo() {const set = new Set(); set.add({a: 'a'})},并且一旦我们运行函数foo,由于无法再次访问set,它和我们添加的对象即使我们没有使用WeakSet,这一切都会被正确地收集起来?
  • 是的,那一套会被 GC 处理掉。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
  • 2016-03-11
相关资源
最近更新 更多