在.NET / Java中,您可以在具有与垃圾收集器相关的魔术属性的类中包装引用(例如,WeakReference等...)
对于“不遵循”引用的概念,似乎没有这样的类 - 即告诉垃圾收集器从指定的引用开始存在对象的复杂子图并且不应该收集它的方法。 (所以不要浪费cpu周期来对该子图进行标记和扫描)。
有谁知道为什么这个功能不存在?
非常感谢
答案 0 :(得分:1)
这个功能不存在,因为它不会做你想的。标记和扫描收集器遍历对象图并记录应保留的对象。如果你告诉它不要标记一些子图,那么收集器会在它做任何清理工作时丢弃所有这些对象。唯一有用的参考状态是“保持这个”(在主类中锚定的图形中保存一个引用),“扔掉它”(不要保留任何可从那里到达的引用),并且“你可以选择是否抛出这个离开“(WeakReference
)。
答案 1 :(得分:0)
问题是GC的设计是假设一切都已死,找到 live 对象,然后收集其余的。为了让你的想法发挥作用,你必须颠倒这种方法,让GC从一切活着开始,找到死对象。
考虑这种情况。你有一个对象A,这是你特别的“不要导航我的图形”对象。你的图表是A-> B-> C。在找到活动对象的GC中,它无法知道B和C是否存活,因为“不要导航我的图形”标志将阻止它找到B和C.所以A保持活着但是B和C收集。不好。
那么为什么GC会搜索实时对象而不是死对象呢?为了找到活动对象,GC从它知道某些仍然在使用的引用开始(称为根)。这些通常是堆栈上的引用(当前运行的方法中的局部变量),静态引用和其他一些引用。这些根引用的每个对象,递归地追溯到图的末尾,肯定仍在使用中,无法收集。其他一切都是垃圾。
如果你实现了逆方法并假设一切都还活着并试图搜索死对象,你必须查看堆中的每个对象,找出引用它的对象,并追逐该图直到它用完为止或者你找到一个根。如果找到根,则链中的所有内容都是活动的。如果没有,链中的一切都已经死了。
这两种方法的区别在于从根本开始需要的工作少得多。您遵循的每个参考都保证有效。一个对象可能指的是其他一千个对象,但是您只需要从根目录中通过它一次就可以证明它和千个对象是活着的。相反,如果你从未从根目录到达那个对象,你知道它已经死了,而不必导航那些数千个引用。
此外,对象存储它们引用的内容,而不是引用它们的内容。给定一个对象,找出是否有人引用它将需要搜索所有其他对象的引用。或者你可以在每个对象上存储一个裁判列表,但现在每个参考的成本都是内存的两倍。
在.Net中,有GCHandle类,它允许您创建一个被视为根的引用。因此,不会收集对象的子图。但是仍然需要导航子图以了解这些对象是什么。
简而言之,GC的设计就是为了简化和提高性能。如果不标记/扫描对象的子图,则子图中的对象可能会被垃圾回收。这与你想要的相反。
答案 2 :(得分:0)
了解GC行为的最简单方法是去保龄球馆观看球员第一次投球后会发生什么。机器识别仍然站立的所有销钉,将它们移出车道,盲目地清除车道,然后将站在车道上的销钉放回原位。机器不关心哪些引脚被击倒甚至多少(除非所有十个引脚都被击倒,在这种情况下它会立即前进到下一帧)。即使有一种方法可以标记被击倒的引脚,这种标记也无法帮助排针器。
另一件需要考虑的事情是GC框架最基本的优势之一就是没有悬挂引用这样的东西。只要在任何地方存在可到达的引用,对象就会存在,并且在销毁最后一个可到达的引用时将不再存在。为了允许弱引用之类的东西,系统首先识别可以通过强引用访问的所有对象。完成后,系统将查看弱引用列表,并使目标尚未标记为实时的任何弱引用无效。它还将遍历一个覆盖Finalize
的对象列表,并添加该列表中但未在其他任何地方引用的任何项目,以及需要立即清理的对象列表。覆盖Finalize
或存在弱引用的对象将继续存在,直到GC消除可以通过任何方式到达它的任何和所有引用;但是,无论GC何时运行以回收空间,大多数对象都会在覆盖最后一个引用时立即停止存在。