调整List <t> </t>的容量

时间:2013-12-03 12:50:54

标签: c# performance algorithm list memory-management

我用Reflector阅读了.NET4.0的类System.Collections.Generic.List<T>的源代码, 我有一些问题。 这是代码:

    [__DynamicallyInvokable]
    public void Add(T item)
    {
        if (this._size == this._items.Length)
        {
            this.EnsureCapacity(this._size + 1);
        }
        this._items[this._size++] = item;
        this._version++;
    }
    private void EnsureCapacity(int min)
    {
        if (this._items.Length < min)
        {
            int num = (this._items.Length == 0) ? 4 : (this._items.Length * 2);
            if (num > 0x7fefffff)
            {
                num = 0x7fefffff;
            }
            if (num < min)
            {
                num = min;
            }
            this.Capacity = num;
        }
    }
    [__DynamicallyInvokable]
    public int Capacity
    {
        // omitted code

        set
        {
            if (value < this._size)
            {
                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
            }
            if (value != this._items.Length)
            {
                if (value > 0)
                {
                    T[] destinationArray = new T[value];
                    if (this._size > 0)
                    {
                        Array.Copy(this._items, 0, destinationArray, 0, this._size);
                    }
                    this._items = destinationArray;
                }
                else
                {
                    this._items = List<T>._emptyArray;
                }
            }
        }
    }
  • 这是通过将所有元素复制到新数组来调整数组大小的最佳方式还是唯一方法?
  • 为什么用“0x7fefffff”检查“num”?为什么“0x7fefffff”特别?
  • 为什么他们可以直接使用“4”和“0x7fefffff”?他们不是神奇的数字吗?

    感谢。

2 个答案:

答案 0 :(得分:5)

这是原始源代码(对于.NET 4.0,我相信):

    // Ensures that the capacity of this list is at least the given minimum 
    // value. If the currect capacity of the list is less than min, the
    // capacity is increased to twice the current capacity or to min, 
    // whichever is larger. 
    private void EnsureCapacity(int min) {
        if (_items.Length < min) { 
            int newCapacity = _items.Length == 0? _defaultCapacity : _items.Length * 2;
            // Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
            // Note that this check works even when _items.Length overflowed thanks to the (uint) cast
            if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength; 
            if (newCapacity < min) newCapacity = min;
            Capacity = newCapacity; 
        } 
    }

关于你的问题:

  • 是的,您无法调整现有阵列的大小。但是,Array.Resize允许您执行List.Capacity所做的事情,但代码更少。它会为您创建新数组,复制元素并为其分配新数组。
  • 如果查看原始代码,很明显限制是CLR中数组的大小。看起来数组可以长达int.MaxValue个元素,减去0x100000个插槽,可能是阵列开销。我无法真正说明那些插槽的用途。
  • 在原始代码中,它们是常量。 C#编译器不编译对常量的引用。它只存储值。这就是常量在反编译代码中成为幻数的原因。

答案 1 :(得分:3)

  

这是通过将所有元素复制到新数组来调整数组大小的最佳方式还是唯一方法?

是的,这是调整阵列大小的唯一方法。

对于给定大小的数组,只为该数组分配了内存部分,周围的内存可以分配给其他内容,因此您不能简单地扩展内存,需要更大的插槽。

  

为什么用“0x7fefffff”检查“num”?为什么“0x7fefffff”很特别?

请参阅MSDN

  

但是,阵列仍将限制为总共40亿个元素,并且在任何给定维度中的最大索引为0X7FEFFFFF (对于字节数组和单字节结构数组,为0X7FFFFFC7)

我找不到任何文件来指示为什么 0X7FEFFFFF是最大允许的大小(他们可能有一些不错的理由来达到这样的限制)。

  

为什么他们可以直接使用“4”和“0x7fefffff”?他们不是神奇的数字吗?

const可能在这里有意义。

这可能不是完全原始代码的样子(如usr所提到的,它可能已被反编译),所以确实可能const用了。

如果它恰好是原始代码的样子,我相信只有开发人员可以告诉你他们为什么会这样做。