20.List初始化效率比较
20.1 题目
//代码1:
List<int> list = new List<int>();
for (int i = 0; i < 50; i++)
{
list.Add(i);
}
//代码2:
List<int> list2 = new List<int>(50);
for (int i = 0; i < 50; i++)
{
list2.Add(i);
}
以上代码,谁的效率更高?为什么?
20.2 深入解析
代码2的效率更高。
因为List的本质是数组,在初始化时,如果不明确指定分配多少容量,它会不断扩容。扩容会带来效率的降低和垃圾的产生。
详细解释
效率的降低:
- 扩容时,
List需要将旧数组中的元素复制到一个新的更大的数组中。这个过程称为“搬家”,需要时间和资源。 - 默认情况下,当
List的容量不够时,容量会按照一定的倍数增长(通常是两倍)。这个过程需要不断地重新分配内存并复制数据,从而导致性能的降低。
- 扩容时,
垃圾的产生:
- 每次扩容时,旧数组就变成了垃圾,需要垃圾回收机制来处理。这会增加垃圾回收的负担,进一步影响性能。
- 在代码1中,
List<int> list1是在没有指定初始容量的情况下创建的。当添加元素时,List需要不断地扩容。 - 在代码2中,
List<int> list2在创建时指定了初始容量50。因此可直接分配足够空间容纳本次循环中的全部元素,避免扩容。
总结
通过在创建 List 时指定初始容量,可以显著提高性能,避免不必要的扩容操作和垃圾产生。因此,在可以预估集合大小的情况下,最好在初始化时指定容量,这样可以优化性能,提高效率。
20.3 答题示例
代码2效率更高。原因是
List<T>的底层是数组,若未指定容量(如代码1),在添加元素过程中会不断触发自动扩容,每次扩容都需要:
- 分配新数组(通常是原容量的2倍)
- 将旧数组内容拷贝到新数组
- 回收旧数组造成 GC 压力
代码2通过
new List<int>(50)预先分配了容量,避免了扩容开销,因此性能更优,尤其在循环次数较大时优势更明显。优化建议:能预估容量的集合建议提前指定容量大小。
20.4 关键词联想
- List扩容机制
- 内存拷贝(CopyTo)
- GC压力
- 初始化容量
- 性能优化
- Add引发Realloc
- 集合性能提升策略
- 构造函数容量参数
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com