关于List源码的分析

  • Post author:
  • Post category:其他


List是c#中的一个最常见的可伸缩数组组件,不用手动去分配数组大小

初始容量是0

优点:使用索引方式提取数组很快,通用性高

缺点:扩容时会很糟糕,每次针对数组进行new操作都会造成内存垃圾,给gc带来巨大负担。效率不高


常用接口分析


(1)Add接口

给定对象添加到列表的末尾,列表的大小+1

容量不够,将会增加到当前容量的两倍

4,8,16,32,64,128

溢出(大约2gb)之前,会允许列表增长到最大容量

(2)Remove接口

删除给定索引处的元素,列表大小减1

返回此列表范围内给定值首次出现的索引,该列表从头向尾向前搜索

用Array.IndexOf执行搜索

使用Object.Equals方法将列表中的元素与给定值进行比较

删除原理是使用Array.Copy对数组进行覆盖

O(n)

(3)Insert接口

给定索引处将元素插入此列表,列表大小增加1

如果需要,在插入新元素之前,列表的容量会增加一倍

使用Array.Copy进行复制数组,将数组里指定元素后面的所有元素向后移动一个位置

(4)[]接口(public T this[int index])

这里是直接使用数组的索引方式获取元素

(5)Clear接口

调用时并不会删除数组,而只是将数组中的元素设置为0或者null,而且size也设置成0.

(6)Contains接口,Find接口

用线性查找方式比较元素,对数组执行循环操作

(7)ToArray接口(public T[] ToArray())

重新创造了一个指定大小的数组,将本身数组上的内容复制到新数组再返回,如果使用过多,会造成大量内存的分配,在内存留下很多无用的垃圾。

(8)Enumerator接口

这里也就是循环遍历的意思

每次获取迭代器时,Enumerator都会被创造出来,如果大量使用迭代器,比如foeach,就会产生大量的垃圾,所以尽量不要使用foreach,因为List的foreach会增加Enumerator实例,最后被GC,虽然后面net4.0修复了这个问题,但还是不建议大量使用。而且foreach不能边遍历边修改。

(9)Sort接口

内部使用快排进行排序,O(nlogn)


总结


好用但是效率不高

1.List里的接口都是没有做过任何形式的优化的,使用的都是顺序迭代的方式,过于频繁的使用,效率会降低,也会造成内存冗余,使得GC要承担更多压力

2.List只是通用性高,大部分算法都是使用的是线性复杂度的算法,当遇到规模较大的计算量级时,这种线性算法会导致cpu的内存大量消耗。

3.List内存分配不合理,元素不断增加会多次重新分配数组,导致原来的被遗弃,gc会造成回收压力

4.线程不安全,并没有对多线程做任何加锁或者其他同步操作


改进


1.自己写一套

2.创建List实例的时候告诉List最多会有多少元素在里面

3.多线程使用期间应加上安全机制



版权声明:本文为qq_42385019原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。