【问题标题】:Clearing a private collection or setting it to null?清除私人收藏或将其设置为空?
【发布时间】:2012-07-30 07:54:17
【问题描述】:

我有一个可变类,里面有一个私有的List<T> 字段。在我班级的Reset() 方法中,我应该使用其Clear() 方法清除列表还是只为其字段分配一个新列表?请注意,该列表不是公开的,仅由类本身使用。因此,分配一个新列表应该使旧列表无法访问。自从Clear() 方法is an O(n) operation 以来,我想知道在它上面分配一个新列表有什么缺点。

【问题讨论】:

    标签: c# collections garbage-collection null


    【解决方案1】:

    我能想到的唯一缺点是,如果您需要再次使用该列表,则必须为其分配新空间。

    清空它只会使列表及其内容(假设没有其他引用)符合 GC 条件。清除它会删除项目,但保留分配的内存。

    就我个人而言,我倾向于将它归零,因为即使我再次需要它,大小也会完全改变。

    更新:关于下面的 cmets,您声明这些对象将在对象池中进行管理。我建议创建一个小型分析控制台应用程序来获得最终答案。现在讨论的是您的实现细节和对象池的预期用途,这很容易改变答案。

    一般来说,如果您的列表长度变化不大并且总是需要,我会使用Clear 来避免为列表分配新内存。如果列表长度可能会发生很大变化,或者有时使用量很少 - 我倾向于将其置空以回收内存并通过列表的延迟实例化获得一些小好处。

    【讨论】:

    • 那么如果我有一个包含 2k 字节的字节列表,哪个会更快?我,调用 Clear 或 GC,进行重新分配?我问这个是因为我有大约 1-2k 的对象,里面有这些列表,所以我想确定哪个会更好,性能方面。
    • @d4wn 就我个人而言,在您证明这是一个问题之前,我不会担心性能。这取决于您要对列表执行的操作。如果不再需要这些项目,但您可能需要列表大小或希望避免为列表增长重新分配内存,我会Clear。如果您以后不关心列表或者它可能会缩小很多,我会list = null; list = new List<T>()。在任何一种情况下,GC 都会收集 x-many 对象,所以没关系。任何潜在的性能差异都将是 O(n) 迭代与列表增长重新分配之间的差异。
    • 那么,还有一个问题:为什么我要“避免为列表增长重新分配内存”?我为这些对象使用了一个池,只要应用程序正在运行,它们就会被一遍又一遍地重用。每次都进行重新分配听起来很昂贵,但我对 GC 以及这个过程对性能的影响程度了解不多。
    • 如果您正在汇集预先确定大小的List<T> 列表,那么我更倾向于Clear,因为它更能表达意图。通过池化,您希望该项目在返回池中时能够长期存在。清空列表意味着 GC 必须回收以前的列表内存,然后为新列表获取下一个块。我所说的分配是指除非您指定列表容量,否则它会在需要时自动增长。看起来好像您想管理一个池,我建议您自己进行归零与Clear 的分析,这是特定于您的池要求的。 Stopwatch 在这里提供帮助。
    • 所以使用 Clear 的优点是它可以保持列表的容量并避免重新分配,而重新创建它的优点是这种方法提供了惰性使用的好处。因此,如果我不需要该列表(这可能会发生,因为该列表是我正在池化的类的私有成员,所以我不会直接将列表池化)它永远不会被创建。您能否在我接受之前合并您评论的这些内容来更新您的帖子?
    【解决方案2】:

    那么为什么为空呢?这将为您解决问题,让旧列表留在堆上进行垃圾收集,而访问该列表的现有方法可以继续在新的空列表上运行:

    this.FooList = new List<Foo>();
    

    【讨论】:

    • 我也写了“为其字段分配一个新列表”。我使用“nullifying”这个词的原因是因为它使该字段无法访问并允许 GC 收集它。但你是对的,我应该编辑这个问题。无论如何,问题是哪个会更快,它们比另一个有什么优势/劣势。
    • 在 GC 看来,将其归零或重新分配等同于同一件事。如果您将其清空并稍后重新分配,您将获得延迟实例化的轻微好处。
    【解决方案3】:

    Reset 调用之后,我会让对象处于调用构造函数之后的相同状态。

    如果您的构造函数创建了一个新的空List,那么就这样做。如果不行的话null.

    【讨论】:

    • 这就是我试图决定的。在构造函数中设置一次列表并通过清除它反复使用它,或者在需要时懒惰地创建它并在 Reset 中将其设置为 null(或新列表)。
    • @d4wn 在我看来,我不认为性能应该推动这个决定。我认为让它null 和懒加载是最干净的,我会这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 2016-07-12
    • 1970-01-01
    • 1970-01-01
    • 2010-11-12
    相关资源
    最近更新 更多