【问题标题】:Resize capacity of List<T>调整 List<T> 的容量
【发布时间】:2013-12-19 13:02:45
【问题描述】:

我用Reflector阅读了.NET4.0的System.Collections.Generic.List&lt;T&gt;类的源码, 我有一些问题。 代码如下:

    [__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”?它们不是神奇的数字吗?

    谢谢。

【问题讨论】:

  • 作为其他回答此问题的人的说明:0x7fefffff = 2146435071 = 2^31
  • Wiki 说要这样做 en.wikipedia.org/wiki/Dynamic_array。第一个问题。
  • @AdamKewley 实际上 2^31 = 2147483648。
  • @Dukeling 是的,抱歉,我将数字四舍五入到最接近的整数。然而,计算系统需要一个字面的解释,我的错。
  • @AdamKewley:2^31 = 0x80000000。另一方面2^31 - 2^20 - 1 = 0x7feffffff.

标签: c# performance algorithm list memory-management


【解决方案1】:

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

是的,这是调整数组大小的唯一方法。

对于给定大小的数组,只为数组分配那部分内存,周围的内存可以分配给其他东西,所以不能简单地扩展内存,需要更大的插槽。

 

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

MSDN:

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

我找不到任何文档来说明 为什么 0X7FEFFFFF 是允许的最大尺寸(他们可能有一些很好的理由来设置这样的限制)。

 

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

const 在这里可能是有意义的。

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

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

【讨论】:

  • 代码看起来是反编译的。它们可能曾经常量。
  • Constant variables 是矛盾的。 :) 并且正如@usr 指出的那样,它们可能是constants 反射器显示为硬编码值:)
【解决方案2】:

这是原始来源(我相信是 .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# 编译器不编译对常量的引用。它只存储值。这就是为什么常量在反编译代码中变成幻数的原因。

【讨论】:

    猜你喜欢
    • 2010-12-12
    • 1970-01-01
    • 2013-06-24
    • 2013-09-13
    • 1970-01-01
    • 2013-08-23
    • 1970-01-01
    • 2014-10-15
    • 1970-01-01
    相关资源
    最近更新 更多