在.net中,为什么垃圾收集器在超出范围时不会销毁对象?为什么要等到下一个清理过程运行?
答案 0 :(得分:8)
这是一次尝试,由Chris Sells和Chris Tavares在2003年秋天由微软赞助的项目。他们通过向每个对象添加引用计数字段并修改JIT编译器以在引用超出范围时自动递减计数来修改CLR(Rotor版本)。并且当计数变为零时自动运行终结器。
目标已实现,不再需要使用语句。
手术成功,病人死了。这些修改导致严重的性能下降。他们试图在Compuware的帮助下进行诊断,当时他是一家领先的工具供应商。但无法确定下来。发布失败is here的博文,技术详情are here。
此后垃圾收集者得到了更多的尊重。从那时起我就没有进一步的尝试了。
答案 1 :(得分:3)
这需要GC的引用计数形式。 .NET GC属于mark-and-sweep类型。
对象不会超出范围。对对象的引用。并且编译器可以轻松跟踪它,但是对同一个对象有任何其他引用吗?这不是那么微不足道。
引用计数有两个主要问题:
答案 2 :(得分:0)
app / system可能正在忙于做其他事情。因此,立即GC运行可能会导致性能下降。系统会尝试确定运行GC的最佳时间。
答案 3 :(得分:0)
嗯,不是处理,而是线程。
主要原因是性能:垃圾收集的过程很昂贵,因此“虚拟机”更喜欢让一些内存“误入歧途”(好吧,不是真的:它仍然可以引用它)并为新对象分配内存需要的时候。但是,它仍会定期运行,因为将记忆误入太长时间也没有任何好处。
垃圾收集算法很多:请参阅here。垃圾收集算法的目的是在运行代码时尽可能少地吸血鬼。在物体超出范围后立即收集垃圾并不符合该法案......
答案 4 :(得分:0)
因为每次分配/更改任何引用(对象成员,变量,集合项等)时都需要检查。并且您需要跟踪对象的所有引用,例如通过存储计数并使其保持最新。这称为引用计数,并且存在许多问题,从一般性能(每个引用分配需要比较和内存访问)到存在并发时的同步开销(如果两个线程同时处理对同一对象的引用会发生什么?)到无法检测周期(如果A指的是B,B指的是A,参考计数都不会降到0,所以你会泄漏内存,或者你仍然需要一个“完整”的GC,如下所述)。
相反,大多数垃圾收集器只是让引用来去,如果需要收集,它们会遵循当前存在的引用来确定正在使用哪些对象(分别可能正在使用中)因为它们是可达的)并释放其余部分。显然,这是很多工作,所以你只是偶尔做一次。有一些更精细的方法可以最大限度地减少每个平均集合的工作,或者更喜欢收集更有可能的堆区域。但是一般问题仍然存在:一旦垃圾成为垃圾就无法找到所有垃圾,因为这意味着每次参考更改时都会走遍整个堆。