1

我用ILSpy反编译了 mscorlib 库,并注意到该List.Clear方法在Array.Clear(this._items, 0, this._size)内部使用。

// System.Collections.Generic.List<T>
/// <summary>Removes all elements from the <see cref="T:System.Collections.Generic.List`1" />.</summary>
public void Clear()
{
    if (this._size > 0)
    {
        Array.Clear(this._items, 0, this._size);
        this._size = 0;
    }
    this._version++;
}

接下来,此Array.Clear方法将所有数组元素设置为零、false 或 null,如其描述的那样。也在List.RemoveRangeArray.Clear方法。

// System.Array
/// <summary>Sets a range of elements in the <see cref="T:System.Array" /> to zero, to false, or to null, depending on the element type.</summary>
/// <param name="array">The <see cref="T:System.Array" /> whose elements need to be cleared.</param>
/// <param name="index">The starting index of the range of elements to clear.</param>
/// <param name="length">The number of elements to clear.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="array" /> is null.</exception>
/// <exception cref="T:System.IndexOutOfRangeException">
/// <paramref name="index" /> is less than the lower bound of <paramref name="array" />.-or-<paramref name="length" /> is less than zero.-or-The sum of <paramref name="index" /> and <paramref name="length" /> is greater than the size of the <see cref="T:System.Array" />.</exception>
/// <filterpriority>1</filterpriority>
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), SecuritySafeCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void Clear(Array array, int index, int length);

是否可以忽略Array.Clear(this._items, 0, this._size)值类型的第一个代码清单中的方法调用?我认为没有必要。我对吗?

这个问题不仅适用于 List,而且适用于其他通用集合。

4

2 回答 2

3

垃圾收集器不知道超出_size的元素在逻辑上是不可达的。它所看到的只是一个充满对象句柄的数组,因此它必须保持这些对象中的每一个都处于活动状态。出于这个原因,实际上将所有句柄设置null为清除容器的必要部分,以允许垃圾收集器清理刚刚从列表中删除的对象(如果程序的其他部分没有它们的句柄)。

对于原始类型 ( List<int>),这不是必需的,但 .NET 不允许专门化泛型类型。值类型可以包含句柄,因此即使 .NET 有专门化,也无法对它们进行优化。

于 2012-09-28T13:28:50.597 回答
0

对于数组没有。对于列表,您可以。

请记住,数组会预先分配内存,因此您需要将这些元素设置为默认值(在数字的情况下,它是 0)。

现在,在列表的情况下,请记住您有一个指向列表第一个元素的标题指针,您可以做的就是将列表标题指向 null,如果需要,将长度变量设置为 0,这样您的列表将是空的(清除)而不触及所有元素。现在这是在ADT链表上。

在 .NET CLR List 上,通过实现很清楚 Clear 操作是 O(N) 并且需要遍历列表以释放引用,这是为什么呢?我认为 java规范(尽管这是 .NET)可以让您了解原因:

清除节点之间的所有链接是“不必要的”,但是: - 如果丢弃的节点超过一代,则有助于分代 GC - 即使存在可访问的迭代器,也肯定会释放内存

于 2012-09-28T13:16:28.797 回答