19

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

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

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

4

5 回答 5

7

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

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

我不确定我 100% 理解这三个项目符号,所以我犹豫猜测哪个(如果有的话)最接近。

于 2009-04-23T08:32:52.753 回答
5

不确定我是否理解您的问题,但您可以查看 Java 中 WeakReference 类及其超类 Reference 的实现。它有很好的注释,您可以看到它有一个由 GC 特殊处理的字段和另一个由 VM 直接使用的字段。

于 2009-04-23T11:48:54.153 回答
5

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

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

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

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

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

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

于 2013-08-02T23:20:38.677 回答
4

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

于 2009-04-23T09:14:53.150 回答
0

我认为,正常的方法是让系统维护某种弱引用列表。当垃圾收集器执行时,在删除死对象之前,系统会遍历弱引用列表并使其目标未被标记为活动的任何引用无效。根据系统的不同,这可能发生在系统临时复活符合立即终结条件的对象之前或之后(在 .net 的情况下,有两种WeakReference——其中一种在系统扫描终结器之前被有效处理,这意味着当它的目标有资格完成最终确定时它将变得无效,并且其中一个在之后处理)。

顺便说一句,如果我正在设计一个基于 gc 的框架,我会添加一些其他好处:(1) 一种将引用类型存储位置声明为持有其他人主要感兴趣的引用的方法,以及 (2)其中的各种WeakReference可能表明对对象的唯一引用是“其他人感兴趣的”存储位置。虽然WeakReference是一种有用的类型,但将弱引用转换为强引用的行为可能会阻止系统识别出没有人会介意目标消失的情况。

于 2012-06-09T18:09:58.743 回答