如何实施弱参考?

Mic*_*bon 17 .net java weak-references internals

我想知道弱引用是如何在内部工作的,例如在.NET或Java中.我的两个一般想法是:

  1. "侵入性" - 添加对最顶级类(对象类)的弱引用列表.然后,当一个对象被销毁时,可以迭代所有弱引用并将其设置为null.
  2. "非侵入式" - 维护对象指向弱引用列表的哈希表.当为对象B创建弱引用A时,将在哈希表中修改或创建一个条目,其键将是指向B的指针.
  3. "Dirty" - 为每个对象存储一个特殊的哈希值,当对象被销毁时,它将被归零.弱引用将复制该哈希值,并将其与对象的值进行比较,以检查对象是否处于活动状态.但是,当直接使用时,这会导致访问冲突错误,因此我需要有一个具有该哈希值的附加对象.

这些解决方案中的任何一个看起来既干净又效 有谁知道它是如何实际完成的?

Mar*_*ell 6

在.NET中,当WeakReference创建a时,会要求GC提供表示引用的句柄/不透明标记.然后,在需要时,WeakReference使用此句柄询问GC该句柄是否仍然有效(即原始对象仍然存在) - 如果是,则可以获取实际的对象引用.

所以这是构建一个针对对象地址的令牌/句柄列表(并且可能在碎片整理期间维护该列表等)

我不确定我是否100%理解三颗子弹,所以我不敢猜测哪一颗(如果有的话)最接近.

  • 压缩GC无论如何都需要为该问题提供解决方案,因为它也一直在移动物体. (2认同)

Jos*_*Lee 5

Python 的PEP 205对弱引用在 Python 中的行为方式进行了很好的解释,这为如何实现弱引用提供了一些见解。由于弱引用是不可变的,因此您可以为每个对象只有一个弱引用,并根据需要向其传递引用。这样,当对象被销毁时,只需要使一个弱引用失效。


pgr*_*ras 5

不确定我理解你的问题,但你可以看一下WeakReference类及其Java中的超类Reference的实现.它评论很好,您可以看到它有一个由GC专门处理的字段和另一个由VM直接使用的字段.


pfa*_*con 5

似乎弱引用的实现在行业中是保密的;-)。例如,截至目前,维基百科文章缺乏任何实现细节。并查看上面的答案(包括已接受的答案):“查看源代码”或“我认为”;-\。

在所有答案中,只有引用 Python 的 PEP 205 的答案是有见地的。正如它所说,对于任何单个对象,如果我们将 weakref 视为实体本身,则最多只能有一个弱引用。

其余部分描述了 Squirrel 语言的实现。所以,weakref 本身就是一个对象,当你在某个容器中放置一个对象的弱引用时,你实际上是放置了对weakref 对象的引用。每个 ref-countable 对象都有一个字段来存储指向其弱引用的指针,在实际请求该对象的弱引用之前,该指针为 NULL。每个对象都有请求weakref的方法,它要么从字段返回现有(单个)weakref,要么创建它并在该字段中缓存。

当然,weakref 指向原始对象。因此,您只需要遍历所有处理对象引用的可用位置,并添加对弱引用的透明处理(即自动取消引用它)。(“透明”替代方案是添加虚拟“访问”方法,该方法将成为大多数对象的身份,并为弱引用实际取消引用。)

并且由于对象具有指向其弱引用的指针,因此该对象可以在自己的析构函数中将弱引用设为 NULL。

这个实现非常干净(没有魔法“调用 GC”之类的东西)并且有 O(1) 的运行时成本。当然,它对内存非常贪婪——需要为每个对象添加 +1 指针字段,即使通常对于 90+% 的对象来说都是 NULL。当然,VHLL 每个对象已经有很大的内存开销,并且可能有机会压缩不同的“额外”字段。例如,对象类型通常是一个小的枚举,因此可以将类型和某种弱引用引用合并到单个机器字中(例如,将弱引用对象保留在单独的领域中,并使用索引)。