我想知道弱引用是如何在内部工作的,例如在.NET或Java中。我的两个一般想法是:
这些解决方案中的任何一个看起来既干净又效率高。有谁知道它是如何实际完成的?
答案 0 :(得分:6)
在.NET中,当创建WeakReference
时,会要求GC提供表示引用的句柄/不透明标记。然后,在需要时,WeakReference
使用此句柄询问GC该句柄是否仍然有效(即原始对象仍然存在) - 如果是,则可以获得实际的对象引用。
所以这是构建一个针对对象地址的令牌/句柄列表(并且可能在碎片整理期间维护该列表等)
我不确定我是否100%理解这三颗子弹,所以我不敢猜测哪一颗(如果有的话)最接近。
答案 1 :(得分:5)
不确定我是否理解了您的问题,但您可以查看类WeakReference及其Java中的超类Reference的实现。它评论很好,您可以看到它有一个由GC专门处理的字段和另一个由VM直接使用的字段。
答案 2 :(得分:3)
似乎弱行业的实施在业内是保密的;-)。例如,截至目前,wikipedia article缺少任何实现细节。看看上面的答案(包括接受的):“去看源头”或“我想”; - \。
在所有答案中,只有引用Python的PEP 205的答案才具有洞察力。正如它所说,对于任何单个对象,如果我们将weakref视为一个实体本身,最多只能有一个弱引用。
其余的描述了Squirrel语言的实现。因此,weakref本身就是一个对象,当你对某个容器中的一个对象进行弱引用时,你实际上会引用weakref对象。每个ref-countable对象都有字段来存储指向其weakref的指针,该指针为NULL,直到实际请求对该对象的weakref为止。每个对象都有方法来请求weakref,它返回字段中的现有(singleton)weakref,或者在字段中创建它并缓存。
当然,weakref指向原始对象。因此,您只需要通过处理对象引用的所有可用位置,并添加对weakref的透明处理(即自动取消引用它)。 (“透明”替代方法是添加虚拟“访问”方法,该方法将成为大多数对象的标识,以及弱反射的实际解除引用。)
由于对象具有指向其weakref的指针,因此该对象可以在自己的析构函数中对weakref进行NULL化。
这个实现非常干净(没有神奇的“调用GC”和东西)并且具有O(1)运行时成本。当然,它非常贪婪的内存 - 需要为每个对象添加+1指针字段,即使通常为90 +%对象为NULL。当然,VHLL每个对象已经有大量的内存开销,并且可能有机会压缩不同的“额外”字段。例如,对象类型通常是一个小枚举,因此可以将类型和某种弱引用合并到单个机器字中(例如,将weakref对象保存在单独的竞技场中,并使用索引)。
答案 3 :(得分:2)
Python的PEP 205可以很好地解释弱引用在Python中的行为方式,并且可以深入了解如何实现它们。由于弱引用是不可变的,因此每个对象只能有一个,您可以根据需要传递引用。因此,当对象被销毁时,只需要使一个弱引用无效。
答案 4 :(得分:0)
我认为,正常的方法是让系统维护某种弱引用列表。当垃圾收集器执行时,在删除死对象之前,系统会遍历弱引用列表,并使目标尚未被标记为实时的任何引用无效。根据系统的不同,这可能会在系统暂时恢复有资格立即完成的对象之前或之后发生(在.net的情况下,有两种WeakReference
- 其中一种在有效处理之前有效处理系统扫描终结器,这意味着当它的目标有资格完成时它将变为无效,其中一个在之后被处理。
顺便提一下,如果我正在设计一个基于gc的框架,我会添加其他几个好东西:(1)一种声明引用类型存储位置的方法,因为它持有一个主要的引用其他人感兴趣的,以及(2)各种WeakReference
可能表明对象的唯一引用是“对其他人”感兴趣的存储位置。尽管WeakReference
是一种有用的类型,但是将弱引用转换为强引用的行为可能会阻止系统认识到如果目标消失,没有人会介意。