参考循环的实际例子是什么? [英] What are the practical examples of reference cycles?

查看:17
本文介绍了参考循环的实际例子是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

垃圾收集器具有处理引用循环的功能.据我了解,这对于所有带有 GC 的语言都是必要的.

Garbage collectors have functionality to deal with reference cycles. As far, as I understand, this is necessary for all languages with GC.

但我不明白,为什么不能创建语言避免引用循环,必要时使用一些弱引用.

But I do not understand, why there can not be created language avoiding reference cycles, using some weak references, if necessary.

编程中不可避免的引用循环的真实例子是什么?

What are the real life examples of unavoidable reference cycles, arising in programming?

推荐答案

你不能创建一种避免引用循环的编程语言,因为这是应用程序程序员的责任,而不是创建循环.您只能创建一种要求程序员始终承担该责任的语言.

You can not create a programming language avoiding reference cycles, as it would be the responsibility of the application programmer, not to create the cycles. You could only create a language which requires the programmer to always take that responsibility.

这是允许或不允许循环的数据结构的基本设计.例如.在 Java 中,List 是引用列表,因此,直接或间接存储 List 本身没有问题.但是举一个更直接的例子,对于双向链表,每个节点都有一个指向它的下一个节点和它的前一个节点的指针.这已经足以形成参考循环:

It’s the fundamental design of the data structures which may allow cycles or not. E.g. in Java, a List is a list of references, therefore, there is no problem in storing a List in itself, directly or indirectly. But to name a more straight-forward example, with a doubly linked list, each node has a pointer to its next node and its previous node. This is already enough to form reference cycles:

 ┌──────┐             ┌──────┐             ┌──────┐             ┌──────┐             
 │      │ -next-----> │      │ -next-----> │      │ -next-----> │      │
 │ Node │             │ Node │             │ Node │             │ Node │
 │      │ <-previous- │      │ <-previous- │      │ <-previous- │      │
 └──────┘             └──────┘             └──────┘             └──────┘

这已经形成了多个循环,两个相邻节点之间的短循环通过它们的 previousnext 引用,但也在其他节点之间间接形成.

This is already forming multiple loops, short loops between two adjacent nodes via their previous and next references, but also indirectly between the other nodes.

要通过弱引用切断这些循环,Node 类的设计者必须决定是制作 next 还是 previous 引用虚弱的.它们中的任何一个都会破坏其中一个基本功能:

To cut these loops via weak references, the designer of the Node class would have to decide whether to make the next or previous reference weak. Either of them would destroy one of the fundamental functionality:

  • 如果您有对第一个节点的引用,则可以通过 next 引用链到达并遍历所有节点
  • 如果你有对最后一个节点的引用,你可以通过 previous 引用链到达并遍历所有节点
  • 事实上,对 任何 个链接节点的引用足以到达所有节点
  • 如果所有节点都无法访问,则所有节点都可以进行垃圾回收
  • If you have a reference to the first node, you can reach and traverse all nodes via a chain of next references
  • If you have a reference to the last node, you can reach and traverse all nodes via a chain of previous references
  • In fact, having a reference to any of the chained nodes is sufficient to reach all nodes
  • If all nodes are unreachable, all nodes can get garbage collected

如果您声明两个引用之一为弱引用,则不能假设对一个节点的引用使所有节点都保持活动状态.如果 next 很弱,您需要始终保持对最后一个节点的引用,以防止突然删除下一个节点.如果 previous 很弱,则必须始终保持对第一个节点的引用.

If you declare one of the two references weak, you can not assume that a reference to one node keeps all nodes alive anymore. If next was weak you were required to always keep a reference to the last node to prevent sudden removal of next nodes. If previous was weak, you had to keep a reference to the first node all the time.

因此,要求开发人员始终通过弱引用切断循环会导致对方式的基本限制,必须设计软件.再举一个例子,考虑一个注册了监听器的组件,当事件发生时会修改该组件(或另一个组件引用前者),从而形成一个循环循环.使侦听器引用变弱意味着它可能会无缘无故地突然消失.

So requiring the developer to always cut loops via weak references would cause fundamental restrictions to the way, the software has to be designed. As another example, consider a component to which you register a listener will modify the component when an event happened (or another component having a reference to the former), therefore forming a cyclic loop. Making the listener reference weak would imply that it could suddenly disappear without a cause.

也就是说,即使是弱引用本身也是垃圾收集器在进行图遍历时自然提供的一个特性,因为只有那些在发现它们的存在时才能廉价地采取行动.引用计数系统可以在发现最后一个/唯一存在的强引用已被删除时轻松释放对象,但是当对象已被删除时,它需要对所有现有弱引用进行额外的记录以清除它们释放.

That said, even the weak references themselves are a feature that is naturally provided by garbage collectors doing graph traversal, as only those can cheaply act when discovering their existence. A reference counting system can easily free an object when it discovers that the last/only existing strong reference has been removed, but it would need additional bookkeeping of all existing weak references to clear them when the object has been freed.

这就是引用计数不再有意义的地方.实现起来不再简单(这是唯一的优点),同时效率低下,因为在遍历对象图时,比如遍历链表,你必须永久更新引用计数器(在一个线程中如果您的语言支持多线程,这是一种安全的方式),而遍历垃圾收集器仅在必须检查可回收内存时才需要做一些事情.而且它只需要遍历活着的对象,因此它可以无所事事的时间越长,它在下一个循环中的工作就越少.

This is the point, where reference counting simply makes no sense anymore. It wouldn’t be simple to implement anymore (which is the only advantage), while being inefficient at the same time, as when traversing an object graph, like iterating over the linked list, you permanently have to update reference counters (in a thread safe way if your language supports multi-threading), whereas a traversing garbage collector only has to do something when it has to check for reclaimable memory. And it only has to traverse alive objects, thus the longer it can get away with doing nothing, the less work it will have on the next cycle.

这篇关于参考循环的实际例子是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆