C#如何为列表动态分配内存<;T>;?
从回答到 理论上,List的当前实现中可以存储的最大元素数为Int32.MaxValue——略多于20亿C#如何为列表动态分配内存<;T>;?,c#,.net,list,memory,dynamic-memory-allocation,C#,.net,List,Memory,Dynamic Memory Allocation,从回答到 理论上,List的当前实现中可以存储的最大元素数为Int32.MaxValue——略多于20亿 我们看到一张单子可以包含大量的项目。我假设编译器不会为List的每一个新实现腾出20亿倍于t的空间,那么列表是如何动态增长的呢?它有指向内存中非连续空间的指针吗?您的假设是正确的,编译器不分配任何内容。列表类在内部使用数组来存储元素,并在每次调用添加时检查数组的大小是否足够,如您所见: 公共作废添加(T项){ 如果(_size==_items.Length)确保可恢复性(_size+1);
我们看到一张单子可以包含大量的项目。我假设编译器不会为
List
的每一个新实现腾出20亿倍于t
的空间,那么列表是如何动态增长的呢?它有指向内存中非连续空间的指针吗?您的假设是正确的,编译器不分配任何内容。列表
类在内部使用数组来存储元素,并在每次调用添加时检查数组的大小是否足够,如您所见:
公共作废添加(T项){
如果(_size==_items.Length)确保可恢复性(_size+1);
_项目[_size++]=项目;
_版本++;
}
私人无效保证资本(整数最小值){
如果(_项目长度Array.maxraraylength)newCapacity=Array.maxraraylength;
如果(新容量<最小值)新容量=最小值;
容量=新容量;
}
}
实现该类是为了在引擎盖下使用内部T[]
数组。如果使用构造函数初始化它,它将分配指定大小的数组。如果使用默认构造函数,则默认容量为4,但在本例中,仅在第一次添加时才分配数组
每次向列表中添加元素时,它都会首先检查容量是否已达到(即现有的计数是否等于容量)。如果是这样,它将创建一个大小为前一个数组两倍的新数组,将所有现有元素复制到该数组中,然后继续写入新元素。这将在后续元素添加时无限期地发生,直到达到您引用的硬限制(Int32.MaxValue
)
就性能而言,这意味着添加一个元素是O(1)或O(n)操作,这取决于是否需要增加容量(如下所述)。但是,由于容量在需要增加时会翻倍,因此随着列表的增大,这种重新分配的频率会呈指数级下降。例如,从4开始,容量增加将发生在4、8、16、32、64、128等元素。因此,调用Add
n次时,重新分配的总成本大约为4 + 8. + 16 + … + n/8 + n/4 + n/2,仍然对应于O(n)
下面的示例显示了内部数组在一系列加法操作中的状态:
// ┌┐
var list = new List<char>(); // ││ Count: 0
// └┘ Capacity: 0
// ┌───┬───┬───┬───┐
list.Add('h'); // │ h │ ░ │ ░ │ ░ │ Count: 1
// └───┴───┴───┴───┘ Capacity: 4
// ┌───┬───┬───┬───┐
list.Add('e'); // │ h │ e │ ░ │ ░ │ Count: 2
// └───┴───┴───┴───┘ Capacity: 4
// ┌───┬───┬───┬───┐
list.Add('l'); // │ h │ e │ l │ ░ │ Count: 3
// └───┴───┴───┴───┘ Capacity: 4
// ┌───┬───┬───┬───┐
list.Add('l'); // │ h │ e │ l │ l │ Count: 4
// └───┴───┴───┴───┘ Capacity: 4
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('o'); // │ h │ e │ l │ l │ o │ ░ │ ░ │ ░ │ Count: 5
// └───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 8
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
list.Add(' '); // │ h │ e │ l │ l │ o │ │ ░ │ ░ │ Count: 6
// └───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 8
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('w'); // │ h │ e │ l │ l │ o │ │ w │ ░ │ Count: 7
// └───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 8
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('o'); // │ h │ e │ l │ l │ o │ │ w │ o │ Count: 8
// └───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 8
// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('r'); // │ h │ e │ l │ l │ o │ │ w │ o │ r │ ░ │ ░ │ ░ │ ░ │ ░ │ ░ │ ░ │ Count: 9
// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 16
// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('l'); // │ h │ e │ l │ l │ o │ │ w │ o │ r │ ░ │ ░ │ ░ │ ░ │ ░ │ ░ │ ░ │ Count: 10
// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 16
// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('d'); // │ h │ e │ l │ l │ o │ │ w │ o │ r │ l │ d │ ░ │ ░ │ ░ │ ░ │ ░ │ Count: 11
// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 16
//┌┐
var list=新列表();//││ 计数:0
// └┘ 容量:0
// ┌───┬───┬───┬───┐
列表。添加('h');//│ H│ ░ │ ░ │ ░ │ 计数:1
// └───┴───┴───┴───┘ 容量:4
// ┌───┬───┬───┬───┐
列表。添加('e');//│ H│ E│ ░ │ ░ │ 计数:2
// └───┴───┴───┴───┘ 容量:4
// ┌───┬───┬───┬───┐
列表。添加('l');//│ H│ E│ L│ ░ │ 计数:3
// └───┴───┴───┴───┘ 容量:4
// ┌───┬───┬───┬───┐
列表。添加('l');//│ H│ E│ L│ L│ 计数:4
// └───┴───┴───┴───┘ 容量:4
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('o');//│ H│ E│ L│ L│ o│ ░ │ ░ │ ░ │ 计数:5
// └───┴───┴───┴───┴───┴───┴───┴───┘ 容量:8
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
列表。添加(“”);//│ H│ E│ L│ L│ o│ │ ░ │ ░ │ 计数:6
// └───┴───┴───┴───┴───┴───┴───┴───┘ 容量:8
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
列表。添加('w');//│ H│ E│ L│ L│ o│ │ W│ ░ │ 计数:7
// └───┴───┴───┴───┴───┴───┴───┴───┘ 容量:8
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('o');//│ H│ E│ L│ L│ o│ │ W│ o│ 计数:8
// └───┴───┴───┴───┴───┴───┴───┴───┘ 容量:8
// ┌───┬───┬───┬───┬───┬───┬──?
// ┌┐
var list = new List<char>(); // ││ Count: 0
// └┘ Capacity: 0
// ┌───┬───┬───┬───┐
list.Add('h'); // │ h │ ░ │ ░ │ ░ │ Count: 1
// └───┴───┴───┴───┘ Capacity: 4
// ┌───┬───┬───┬───┐
list.Add('e'); // │ h │ e │ ░ │ ░ │ Count: 2
// └───┴───┴───┴───┘ Capacity: 4
// ┌───┬───┬───┬───┐
list.Add('l'); // │ h │ e │ l │ ░ │ Count: 3
// └───┴───┴───┴───┘ Capacity: 4
// ┌───┬───┬───┬───┐
list.Add('l'); // │ h │ e │ l │ l │ Count: 4
// └───┴───┴───┴───┘ Capacity: 4
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('o'); // │ h │ e │ l │ l │ o │ ░ │ ░ │ ░ │ Count: 5
// └───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 8
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
list.Add(' '); // │ h │ e │ l │ l │ o │ │ ░ │ ░ │ Count: 6
// └───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 8
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('w'); // │ h │ e │ l │ l │ o │ │ w │ ░ │ Count: 7
// └───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 8
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('o'); // │ h │ e │ l │ l │ o │ │ w │ o │ Count: 8
// └───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 8
// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('r'); // │ h │ e │ l │ l │ o │ │ w │ o │ r │ ░ │ ░ │ ░ │ ░ │ ░ │ ░ │ ░ │ Count: 9
// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 16
// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('l'); // │ h │ e │ l │ l │ o │ │ w │ o │ r │ ░ │ ░ │ ░ │ ░ │ ░ │ ░ │ ░ │ Count: 10
// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 16
// ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
list.Add('d'); // │ h │ e │ l │ l │ o │ │ w │ o │ r │ l │ d │ ░ │ ░ │ ░ │ ░ │ ░ │ Count: 11
// └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘ Capacity: 16