在.NET List <T>中将项设置为null是否可用于垃圾收集,这是一个好主意吗?

nlh*_*lh3 21 .net c#

假设我有一个大型列表,其中每个项目都被处理一次,然后在长时间操作期间再也没有看过:

List<T> items;
 // ... some stuff is done with the list then finally

 for(int i = 0; i < items.Count; i++)
 {
     SomeOperation(items[i]);
     //items[i] never used again at this point
     // say i do this:
     // items[i] = null;

 }
Run Code Online (Sandbox Code Playgroud)

如果我取消注释items[i] = null,这会将对象解压缩到索引i并使其可用于垃圾收集吗?

从内存使用的角度来看,这样做是否会更有效率,而不是让GC在以后未使用整个列表时发生.

这忽略了一些问题,比如稍后更改代码,事实证明这些项目是在以后使用的,而且是意外的null wreck havoc.

Ser*_*rvy 28

如果对该对象的唯一可根目录访问是通过该列表,则是,设置该引用null将使该对象符合垃圾回收的条件.

当垃圾收集最终发生时,如果该对象最终被清理而列表本身需要保持不变,那么您将通过该对象的大小减少应用程序的内存占用量.

请注意,为列表中对象的引用分配的内存仍然存在; 它只是它引用的对象的内存,可以清理.

正如许多其他人所提到的,您对此数据结构的使用强烈地表明您不应该首先使用a List,而是使用一个Queue或另一个可比较的数据结构,因为这样可以更有效地满足您的使用需求.

你还需要记住,记忆力很便宜; 人们往往有很多.除非你有成千上万的物品否则会长时间保持活着,所以即使注意到它,这也不足以让你有所改善.你甚至可能无法衡量差异.使用正确的数据结构会给你所有的这些好处,更多的,并且使代码大大简化,更可读/维护.


Ale*_*kov 10

是的,如果list具有对象设置元素的最后引用,则将给定索引设置为null使对象符合GC的条件.

这不是一个好主意:

  • 代码看起来很奇怪.可能很好的评论为什么这样做可以提供帮助.
  • 有可能更好的方式来表达这种行为.

如果您尝试将element设置为null并且分析显示性能/可伸缩性/您正在寻找的任何可测量的增加 - 考虑重写代码以使用更好地表达列表的临时性质的其他更合适的构造(可能是Queue,Stack或者只是IEnumrable与懒惰的评价)

如果它可能是有益的(确保配置文件证明):

  • list包含大型托管对象,如Bitmaps或MemoryStream.在这种情况下,GC有很好的机会实际自动运行和清理对象(假设在迭代期间有更多的分配)
  • list包含保存大型未管理对象的小型托管对象(如全局分配的内存句柄) - 设置为null +正确可能需要Dispose + force GC来触发早期清理(GC不会检测未管理的内存压力)
  • list用作某些数据结构的后备存储,例如自定义Stack,Queue或CircularBuffer作为您自己库的一部分 - 设置元素default(T)/ null是一种智能方法,可以防止您的自定义数据结构延长您的类型不再使用的对象的生命周期.

请注意,在实现自定义数据类型的情况下,您可能必须这样做,因为数据类型的一般契约而不是由于分析 - 即预期Stack在"Pop"之后完全忘记了对象.代码旁边应该有适当的注释internalBuffer[i]=null;- 即"避免在从Stack中删除对象后保持引用".