当采用默认构造函数List<int> value = new List<int>();实例化一个List<T>对象时,.Net Framework只是在内存中申请了一块内存来存放List<T>对象本身(不包含List当中的Items元素)。
当为List<T>对象添加第一个Item元素时,List<T>对象会申请能存储4个Item元素的内存空间,然后将Item元素存放在申请的空间里。
List<T>对象有一个Capacity属性用来表示当前List<T>对象的容量(即当前用于存放Item的内存空间能存放的Item的个数),可以手动的设置它来设定List<T>的容量(Capacity的改变将会导致重新申请内存)。
当List<T>对象的Item元素数量超过了Capacity的数量时,List<T>对象会重新申请一块大小是原来Capacity的两倍的内存空间,然后将当前所有Item元素以及待添加元素复制到新的内存空间中。
通过下列测试代码可以验证List<T>的内存分配原则:
List<int> value = new List<int>(4);
//此时 Count:0 Capacity: 4
for (int i = 1; i <= 5; i++)
{
value.Add(i);
}
//此时 Count:5 Capacity: 8
value.TrimExcess();
//此时 Count:5 Capacity: 5
//remove an item
value.RemoveAt(4);
//此时 Count:4 Capacity: 5
value.TrimExcess();
//此时 Count:4 Capacity: 5---------------Capacity为什么不是4呢?请高手指点
//remove another item
value.RemoveAt(1);
//此时 Count:3 Capacity: 5
value.TrimExcess();
//此时 Count:3 Capacity: 3
value.Clear();
//此时 Count:0 Capacity: 3
value.TrimExcess();
//此时 Count:0 Capacity: 0
知道了内存分配的原则,接下来就得根据这些原则来采用最优的方法保证有限的内存空间能得到合理的运用。归纳起来主要有如下几点:
- 当实例化一个List<T>对象时,如果能预知其Item元素的大致个数,应该在实例化一个List<T>对象的时候设置其Capacity值为接近于Item元素个数的最小值。这样的话可以避免在向List<T>中添加元素的时候,不断的申请内存与元素的复制。
- 当由于不断的调用Remove方法而导致Item元素的个数远远小于Capacity,就会造成内存的浪费。此时可以调用TrimExcess方法释放多余的内存。
【附】如下为MSDN中List类中的部分属性和成员:
// 摘要:
// 获取或设置该内部数据结构在不调整大小的情况下能够容纳的元素总数。
//
// 返回结果:
// 在需要调整大小之前 System.Collections.Generic.List<T> 能够容纳的元素的数目。
//
// 异常:
// System.ArgumentOutOfRangeException:
// System.Collections.Generic.List<T>.Capacity 设置为小于 System.Collections.Generic.List<T>.Count
// 的值。
//
// System.OutOfMemoryException:
// 系统中没有足够的可用内存。
public int Capacity { get; set; }
//
// 摘要:
// 获取 System.Collections.Generic.List<T> 中实际包含的元素数。
//
// 返回结果:
// System.Collections.Generic.List<T> 中实际包含的元素数。
public int Count { get; }
// 摘要:
// 将对象添加到 System.Collections.Generic.List<T> 的结尾处。
//
// 参数:
// item:
// 要添加到 System.Collections.Generic.List<T> 的末尾处的对象。对于引用类型,该值可以为 null。
public void Add(T item);
//
// 摘要:
// 从 System.Collections.Generic.List<T> 中移除特定对象的第一个匹配项。
//
// 参数:
// item:
// 要从 System.Collections.Generic.List<T> 中移除的对象。对于引用类型,该值可以为 null。
//
// 返回结果:
// 如果成功移除 item,则为 true;否则为 false。如果在 System.Collections.Generic.List<T> 中没有找到
// item,该方法也会返回 false。
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public bool Remove(T item);
//
// 摘要:
// 将容量设置为 System.Collections.Generic.List<T> 中的实际元素数目(如果该数目小于某个阈值)。
public void TrimExcess();