列表<t> </t>上的TrimExcess后的容量

时间:2014-01-31 09:21:13

标签: c#

修剪访问用于最小化集合的内存 例如

 List<string> myList = new List<string>();

如果我在列表的修剪访问能力之后包含2个项目将是2

如果TrimExcess容量分别变为4或5或6,则列表包含4或5或6

但如果列表包含3或7或15,为什么在TrimExcess之后容量分别变为4或8或16

即使在此之后我发现了一个更奇怪的行为 如果我运行以下代码

 List<int> myList = new List<int>();
            for (int i = 1; i <= 100; i++)
            {
                myList.Add(1);
                myList.TrimExcess();
                if (myList.Capacity != myList.Count())
                {
                    var different = myList.Capacity;
                }
            }

if语句仅在i = 3

时才为真

任何人都可以让我知道原因

3 个答案:

答案 0 :(得分:10)

以下是List<T>的源代码:

  public void TrimExcess() {
        int threshold = (int)(((double)_items.Length) * 0.9);
        if( _size < threshold ) {
            Capacity = _size;
        }
    }

其中_sizeCount属性的支持字段,而_items.LengthCapacity获取者返回的内容。

基本上,如果没有使用超过10%的阵列插槽,TrimExcess仅将容量设置为Count。这就是为什么在某些测试中Count不等于Capacity


评论中的另一个问题:

   1     List<int> myList = new List<int>
   2         {
   3             1,2,3,4,5,6,7 // equivalent to calling `Add` 7 times
   4         };
   5     Console.WriteLine(myList.Capacity); // prints 8 
   6     myList.TrimExcess();
   7     Console.WriteLine(myList.Capacity); // prints 8

为什么第5行打印8? 空列表以0容量开始。

  • 插入第一个元素时,容量增加到4,即其默认容量。
  • 插入第五个元素时,容量增加到当前容量的两倍。因此,如果容量仍为4,则会达到8。
  • 插入第9个元素时,容量再次加倍,依此类推。

因此,当您插入第5个元素时,容量从4变为8.如果再插入两个元素,您将看到容量从8到16。

为什么第7行打印8?

我的答案的第一部分已经回答了这个问题。

现在我们知道为什么在调用TrimExcess之前容量为8 。 并且因为阵列中未使用的空间*少于10%,TrimExcess什么也不做,容量仍为8。

注意:实际上,有12.5%的未使用空间(阵列中有1个空闲插槽/ 8个可能的插槽)。 但是因为7 * 0.9四舍五入为整数,threshold变为7.并且因为7 < 7返回false,所以没有任何反应。

答案 1 :(得分:2)

取自msdn-Documentation on List.TrimExcess:

  

重新分配和复制大型列表的成本可能相当大,因此,如果列表的容量超过容量的90%,则TrimExcess方法不会做任何事情。这样可以避免因相对较小的收益而产生大量的重新分配成本。

这意味着,在大多数情况下,List.TrimExcess()调用不执行任何操作,因此List.Count和List.Capacity之间存在差异

答案 2 :(得分:1)

我不知道原因,但我决定找出:

public void TrimExcess()
{
    int num = (int) (this._items.Length * 0.9);
    if (this._size < num)
    {
        this.Capacity = this._size;
    }
}

这对我来说很惊讶。如果浪费的空间超过10%,它只会削减集合的容量。看起来像是对常见情况的聪明优化(开发人员在不应该......时调用TrimExcess。)。

修剪自己:

list.Capacity = list.Size;

It turns out this behavior is even documented.