弱引用是如何实现的?

发布于 2024-07-18 22:20:02 字数 396 浏览 6 评论 0原文

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

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

这些解决方案似乎都干净且高效。 有谁知道它实际上是如何完成的?

I wonder how weak references work internally, for example in .NET or in Java. My two general ideas are:

  1. "Intrusive" - to add list of weak references to the most top class (object class). Then, when an object is destroyed, all the weak references can be iterated and set to null.
  2. "Non-intrusive" - to maintain a hashtable of objects' pointers to lists of weak references. When a weak reference A is created to an object B, there would be an entry in the hashtable modified or created, whose key would be the pointer to B.
  3. "Dirty" - to store a special hash-value with each object, which would be zeroed when the object is destroyed. Weak references would copy that hash-value and would compare it with the object's value to check if the object is alive. This would however cause access violation errors, when used directly, so there would need to be an additional object with that hash-value, I think.

Either of these solutions seems clean nor efficient. Does anyone know how it is actually done?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

苏佲洛 2024-07-25 22:20:03

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

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

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

In .NET, when a WeakReference is created, the GC is asked for a handle/opaque token representing the reference. Then, when needed, WeakReference uses this handle to ask the GC if that handle is still valid (i.e. the original object still exists) - and if so, it can get the actual object reference.

So this is building a list of tokens/handles against object addresses (and presumably maintaining that list during defragmentation etc)

I'm not sure I 100% understand the three bullets, so I hesitate to guess which (if any) that is closest to.

沧桑㈠ 2024-07-25 22:20:03

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

Not sure I understood your question, but you can have a look at the implementation for the class WeakReference and its superclass Reference in Java. It is well commented and you can see it has a field treated specially by the GC and another one used directly by the VM.

活泼老夫 2024-07-25 22:20:03

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

Python's PEP 205 has a decent explanation of how weak references should behave in Python, and this gives some insight into how they can be implemented. Since a weak reference is immutable, you could have just one for each object, to which you pass out references as needed. Thus, when the object is destroyed, only one weak reference needs to be invalidated.

独﹏钓一江月 2024-07-25 22:20:03

看来弱引用的实现在业界是保密的;-)。 例如,到目前为止,wikipedia 文章 缺少任何实现细节。 并查看上面的答案(包括已接受的答案):“去看看源代码”或“我认为”;-\ 。

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

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

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

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

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

It seems that implementation of weak references is well-kept secret in the industry ;-). For example, as of now, wikipedia article lacks any implementation details. And look at the answers above (including the accepted): "go look at the source" or "I think" ;-\ .

Of all the answers, only the one referencing Python's PEP 205 is insightful. As it says, for any single object, there can be at most one weak reference, if we treat weakref as an entity itself.

The rest describes Squirrel language implementation. So, weakref is itself an object, when you put weak reference to an object in some container, you actually put reference to weakref object. Each ref-countable object has field to store pointer to its weakref, which is NULL until weakref to that object is actually requested. Each object has method to request weakref, which either returns existing (singleton) weakref from the field, or creates it and caches in the field.

Of course, weakref points to the original object. So, then you just need to go thru all the available places where references to objects are handled and add transparent handling of weakrefs (i.e. automatically dereference it). ("Transparent" alternative is to add virtual "access" method which will be identity for most objects, and actual dereference for weakref.)

And as object has pointer to its weakref, then the object can NULLify the weakref in own destructor.

This implementation is pretty clean (no magic "calls into GC" and stuff) and has O(1) runtime cost. Of course, it's pretty greedy of memory - need to add +1 pointer field to each object, even though typically for 90+% objects that would be NULL. Of course, VHLLs already have large memory overhead per object, and there may be chance to compact different "extra" fields. For example, object type is typically a small enumeration, so it may be possible to merge type and some kind of weakref reference into single machine word (say, keep weakref objects in a separate arena, and use index to that).

想你只要分分秒秒 2024-07-25 22:20:03

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

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

The normal approach, I think, is for the system to maintain some sort of list of weak references. When the garbage collector executes, before dead objects are removed, the system iterates through the list of weak references and invalidates any reference whose target has not been tagged live. Depending upon the system, this may occur before or after the system temporarily resurrects objects which are eligible for immediate finalization (in the case of .net, there are two kinds of WeakReference--one of which is effectively processed before the system scans for finalizers, meaning that it will become invalid when its target becomes eligible for finalization, and one of which is processed after).

Incidentally, if I were designing a gc-based framework, I would add a couple of other goodies: (1) a means of declaring a reference-type storage location as holding a reference that's primarily of interest to someone else, and (2) A variety of WeakReference which would could indicate that the only references to an object are in "of interest to someone else" storage locations. Although WeakReference is a useful type, the act of turning a weak reference into a strong reference may prevent the system from ever recognizing that nobody would mind if its target disappeared.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文