前言:关于学习方法的讨论其实是个比较模糊的概念,对于List的介绍的资料其实已经很多了,但是一般是介绍List本身,我打算分享的是,以温故List为例,来获取新知识的这么一个过程。这里的新知识也不是什么新知识,依旧是算法、泛型、迭代器和GC回收机制等相关术语,只不过通过对List再分析,对这些东西的运用有了些新的认知,我要分享的就是再分析的这么一个过程,姑且允许我将其称为学习方法吧,最起码它是比较适合我的一种学习方法。另外,如果对List已经了解很深或者兴趣不大的话,可以直接跳过1、2节一大堆无聊的测试,直接看总结,甚至跳过此文也未尝不可。

1、  抛砖(List的关键属性Capacity)

前言已经说明是温故List,所以List是什么我也不打算花篇幅再次介绍(更何况一点点的介绍其扩容机制、迭代器和一些内部方法篇幅也会比较大,那就成了介绍List本身了,个人也不见得能总结得多好),这里我温故的就是List的扩容机制。

用反编译工具看过List<T>源码的同学,应该都知道List对象在创建的时候其私有变量_defaultCapacity的值是4。

(此截图来源与ILspy打开的List<T>源码部分,以下关于List<T>的源码部分均是如此)

这个地方让我很长一段时间以为List对象在创建的时候就已经为它内部的数组对象,分配了4个元素,以后调用Add方法就以Capacity*2的线性速度增长,可事实狠狠的打了我一把脸,且看下面这段代码及其运行结果:

回过头来再看源码,发现Capacity属性返回的是内部数组元素的长度,所以刚开始初始化的时候并没有被私有变量初始化,而且就算初始化的时候想给数组4个元素,也不知道List<T>对象中T的实例(T为引用类型的情况下),该分配多少内存CLR是不知道的。

所以我猜测_defaultCapacity赋值给Capacity是在List首次调用Add方法,或者带元素初始化的时候,果不其然,看下面这段代码:

找到源码验证一下:

那么扩容的机制也就理所当然的被我们找到了,就是EnsureCapacity方法,this._szie是当前List元素个数,this._items是内部数组根据Capacity扩容后的数组长度,扩容触发的条件是this._size+1>this._items.Length, 总结说来就是,Capacity的初始值是0,在不主动改变Capacity的情况下使用Add方法会初始化为4,当List元素达到4且继续调用Add的话Capacity就会乘以2变成8,然后如此反复,直到达到2146435071(应该是2^31-1)为止。

2、  引玉(主动操作Capacity是否可带来性能的提升)

通过第1节的分析,想要Add到1亿级别的数量,需要扩容27次,2^27破亿(Capacity从0到4一次,从4到2^27花26次)

那么,正常初始化1亿Int32类型数据需要耗时多久呢?通过下面这段代码可以发现是681ms。

假如我把Capacity初始值设置为1亿,省去那26次扩容带来的时间损耗呢?

为了避免电脑CPU时间段的差异对结果造成影响,我分别运行了3次,不初始化Capacity的情况下耗时700ms左右,初始化Capacity的情况下耗时450ms左右,这么说来是可以带来一定性能的提升的。那么把Capacity设置为3千万,让它扩容两次破亿:

这么一看减少扩容次数是可以带来性能上的提升的。但是这里List集合是值类型的集合,换成引用类型又当如何呢?看如下代码:

减少扩容次数后:

结论依旧是可以带来性能上的提升的。但是个人觉得实际应用中通过设置Capacity去提升性能是不可取的,一方面是使用了对性能的提升并没有显著的改善,况且上亿级别的数据需要缓存的话,一般会使用专门的缓存服务器,另一方面是数据量不好确认,Capacity的设置很难合理,而且使用List的初衷,本来就是为了方便。而且看下面这段代码,我把Test的实例对象放进循环里(实际应用中这也更符合测试思路,毕竟上面的测试List存的都是同一个实例对象),还不等你提升性能,CLR托管内存就爆了,GC都回收不过来了。

3、  总结(知新)

对这次List的重温,更全面的了解其扩容机制,此间带来的收获主要在以下几点:

(1)       Capacity的设置确实能为List的初始化带来性能的提升,但是一般情况下不使用这种方式。

(2)       List扩容的这种机制其实很巧妙,在自定义集合中有值得借鉴的地方。

(3)       意识到托管内存不宜缓存大量数据,同时引导我再次了解GC处理机制。

(4)       List内部变量在方法体的使用中,使用了大量的lock规避引用冲突,这种严谨在多线程、iis线程池等引用的过程中,也是非常值得借鉴的。

(5)       为以后学习其它类似特性的对象提供了思路,假如我现在需要学习一个新的组件或框架,我首先会寻找它的API文档和使用说明、动手测试、大胆猜想、借助源码以及再测试来求证……。

以List为例浅谈C#的学习方法的更多相关文章

  1. 以用户注册功能模块为例浅谈MVC架构下的JavaWeb开发流程

    JavaWeb应用开发,撇开分布式不谈,只讨论一个功能服务应用的开发,无论是使用原生的Servlet/JSP方案,还是时下的SSM架构,都有一套经过工程实践考验的最佳实践,这综合考虑了团队协作.项目管 ...

  2. 以图像分割为例浅谈支持向量机(SVM)

    1. 什么是支持向量机?   在机器学习中,分类问题是一种非常常见也非常重要的问题.常见的分类方法有决策树.聚类方法.贝叶斯分类等等.举一个常见的分类的例子.如下图1所示,在平面直角坐标系中,有一些点 ...

  3. [转]以新浪为例浅谈XSS

    随着网络时代的飞速发展,网络安全问题越来越受大家的关注,而SQL注入的攻击也随着各种防注入的出现开始慢慢的离我们而去,从而XSS跨站脚本攻击也慢慢的开始在最近几年崛起,也应对了’没有绝对的安全’这句话 ...

  4. 浅谈WebService的版本兼容性设计

    在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...

  5. 浅谈Hybrid技术的设计与实现第三弹——落地篇

    前言 接上文:(阅读本文前,建议阅读前两篇文章先) 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 根据之前的介绍,大家对前端与Native的交互应该有一些简单的认识了,很多 ...

  6. 浅谈Hybrid技术的设计与实现第二弹

    前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 接上文:浅谈Hybrid技术的设计与实现(阅读本文前,建议阅读这个先) ...

  7. 浅谈php生成静态页面

    一.引 言 在速度上,静态页面要比动态页面的比方php快很多,这是毫无疑问的,但是由于静态页面的灵活性较差,如果不借助数据库或其他的设备保存相关信息的话,整体的管理上比较繁琐,比方修改编辑.比方阅读权 ...

  8. jsp内置对象浅谈

    jsp内置对象浅谈 | 浏览:1184 | 更新:2013-12-11 16:01 JSP内置对象:我们在使用JSP进行页面编程时可以直接使用而不需自己创建的一些Web容器已为用户创建好的JSP内置对 ...

  9. Android性能优化的浅谈

    一.概要: 本文主要以Android的渲染机制.UI优化.多线程的处理.缓存处理.电量优化以及代码规范等几方面来简述Android的性能优化 二.渲染机制的优化: 大多数用户感知到的卡顿等性能问题的最 ...

随机推荐

  1. MySQL索引与Index Condition Pushdown

    实际上,这个页面所讲述的是在MariaDB 5.3.3(MySQL是在5.6)开始引入的一种叫做Index Condition Pushdown(以下简称ICP)的查询优化方式.由于本身不是一个层面的 ...

  2. 【转】Entity Framework 5.0系列之约定配置

    Code First之所以能够让开发人员以一种更加高效.灵活的方式进行数据操作有一个重要的原因在于它的约定配置.现在软件开发越来复杂,大家也都试图将软件设计的越来越灵活,很多内容我们都希望是可配置的, ...

  3. Java 读取 .properties 配置文件的几种方式

    Java 开发中,需要将一些易变的配置参数放置再 XML 配置文件或者 properties 配置文件中.然而 XML 配置文件需要通过 DOM 或 SAX 方式解析,而读取 properties 配 ...

  4. Centos下mongodb的安装与配置

    安装MongoDB的方法有很多种,可以源代码安装,在Centos也可以用yum源安装的方法. 1.准备工作 运行yum命令查看MongoDB的包信息 yum info mongodb-org (提示没 ...

  5. 常用接口简析1---IEnumerable、IEnumerator简析

    常用接口的解析(链接) 1.IEnumerable深入解析 2.IComparable.IComparable接口解析 3.IList.IList接口解析      引言: IEnumerable和I ...

  6. 圆形的ImageView

    转载自gitHub的ImageView,因为本身就是可用的,也没什么好说的,拷贝回去用就是了,可以设置除了背景,还可以设置边框什么的,比起CardView设置圆角,功能更加强大. import and ...

  7. yum安装jdk

    安装步骤: 1.首先查看java的版本有哪些  :  yum -y list java* 2. 安装目标jdk版本(我选择的是1.7) :   yum -y install java-1.7.0-op ...

  8. win10下安装java jdk,tomcat

    1.安装java jdk 去官网下载java jdk(http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-21 ...

  9. HDU 1698 Just a Hook 线段树+lazy-target 区间刷新

    Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  10. CCF-201312-2-ISBN号码

    问题描述 试题编号: 201312-2 试题名称: ISBN号码 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包 ...