这个答案最初是为Mick撰写的评论而起草的,他声称:
这取决于你使用的.NET版本。在像Xamarin或mono这样的移动平台上,您可能会发现垃圾收集器需要这种帮助才能完成其工作。
这个说法需要事实核查。那么,让我们看看...
.NET
.NET使用分代标记和扫描垃圾回收器。您可以在垃圾回收期间发生了什么中看到算法的摘要。总体而言,它会遍历对象图,如果无法访问对象,则该对象可被擦除。
因此,垃圾回收器将在同一次迭代中正确地识别列表项为可回收项,无论您是否清空列表。没有必要预先解耦对象。
这意味着在.NET的常规实现中清空列表不会帮助垃圾回收器。
注意:如果列表有另一个引用,则清空列表的事实将是可见的。
Mono 和 Xamarin
Mono
事实证明,Mono 也是如此。
Xamarin.Android
同样适用于Xamarin.Android。
Xamarin.iOS
然而,Xamarin.iOS需要额外考虑。特别是,MonoTouch将使用
包装的Objective-C对象,这些对象超出了垃圾回收器的范围。请参见
iOS性能下避免强循环引用。这些对象需要不同的语义。
Xamarin.iOS通过保持缓存来最小化使用Objetive-C对象:
C# NSObjects也是按需创建的,当您调用返回NSObject的方法或属性时。此时,运行时将查看对象缓存,并确定是否已经将给定的Objective-C NSObject暴露给托管世界。如果该对象已经暴露,则返回现有对象,否则将调用以IntPtr作为参数的构造函数来构造该对象。
即使从托管代码中没有引用,系统也会保持这些对象的活动状态:
NSObjects的用户子类通常包含C#状态,因此每当Objective-C运行时对这些对象执行“retain”操作时,运行时都会创建一个GCHandle,即使没有C#可见引用该对象,也会保持托管对象的生命。这样做可以简化很多簿记工作,因为状态将自动保留。因此,在Xamarin.iOS下,如果列表可能包含包装的Objective-C对象,此代码将有助于垃圾回收器。请参见问题
在Xamarin.IOS上如何管理内存,
Miguel de Icaza在他的回答中解释语义是在引用时“保留”对象,在引用为空时“释放”它。
在 Objective-C 方面,“release” 并不意味着销毁对象。Objective-C 使用引用计数垃圾回收器。当我们“retain”对象时,计数器会增加,而当我们“release”对象时,计数器会减少。当计数器达到零时,系统会销毁对象。请参见:
关于内存管理。
因此,在 Xamarin.iOS 中应避免使用循环引用(如果 A 引用 B,B 引用 A,则它们的引用计数不为零,即使无法访问它们)。事实上,忘记解除引用会导致 Xamarin.iOS 中的泄漏... 请参见:
Xamarin iOS memory leaks everywhere。
其他
dotGNU同样使用分代标记和扫描垃圾回收器。
我也看了一下CrossNet(将IL编译为C++的工具),他们似乎也尝试实现了这个功能。我不知道它的表现如何。
null
是您通常应该执行的操作。一旦 GC 意识到List
是不可达的 - 它将意识到它的内容(即底层数组及其所指向的内容)也是不可达的。有些场景中清除可能是值得的 - 例如,如果底层List
有多个引用,并且您不仅想摆脱对此List
的引用,还想确保所有 其他 引用都指向一个空列表(如您在问题中确定的那样)。公正地说,这很少见。 - mjwillsList.Clear()
是无用的。假设是这种情况,那么作者可能既不知道这一点,也可能混淆了List.Clear
与其他在其类中是Dispose
同义词的Clear
方法(例如Stream.Dispose
),并且因此认为List.Clear
是一种可以单独处理列表元素的“深度Dispose”。 - davidbak