前言:关于学习方法的讨论其实是个比较模糊的概念,对于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. concurrent.futures

    concurrent.futures concurrent.futures提供高层次的接口,用来实现异步调用. 这个异步执行可以使用threads(ThreadPoolExecutor)或者proce ...

  2. 图片转换base64数据上传,并且实现预览的简便方法

    对于很多新手来说,实现上传图片并且预览功能,都会感到不知所可,然后开始在网站搜索各种各样的图片上传预览插件,但是有的时候我们只是想简单的实现判断格式,以及预览的功能,使用插件的话,会使得项目的资源空间 ...

  3. .NET之RabbitMQ学习笔记(二)-安装

    安装 1.安装erlang语言环境 因为rabbitmq是基于erlang进行开发,所以需要安装相应的依赖环境,学习中用到的erlang包下载地址:http://www.erlang.org/down ...

  4. 张高兴的 Xamarin.Forms 开发笔记:TapGestureRecognizer 的简单介绍与应用

    最近很少写应用了,一直在忙关于 ASP.NET 的东西(哈欠...).抽点时间对 TapGestureRecognizer 做点总结. 一.简介 TapGestureRecognizer 就是对 Ta ...

  5. javac 实现原理

    javac 概述 javac 是jdk bin目录下的一个脚本. 用于编译 java程序的源代码,但是 其实现的本质 是基于 jdk 标准类库中的 javac类库实现,所以java的编译器实质上是一个 ...

  6. JDK8新特性一览

    转载自:http://blog.csdn.net/qiubabin/article/details/70256683 官方新特性说明地址 Jdk8新特性.png 下面对几个常用的特性做下重点说明. 一 ...

  7. 安卓自定义控件(二)BitmapShader、ShapeDrawable、Shape

    第一篇博客中,我已经Canvas.Paint.Shader.Xfermode这些对象做了总结,而现在这篇文章主要介绍BitmapShader位图渲染,Xfermode如何实际应用,还有形状的绘制.不过 ...

  8. 大数据查询——HBase读写设计与实践

    导语:本文介绍的项目主要解决 check 和 opinion2 张历史数据表(历史数据是指当业务发生过程中的完整中间流程和结果数据)的在线查询.原实现基于 Oracle 提供存储查询服务,随着数据量的 ...

  9. c++头文件重复引用问题

    引子----之前写C++ 时遇到的坑 之前由于Java实在太好用了,C++的工程代码几乎没怎么碰,真的写起来的时候总会有些小bug,这里就对其中的一个进行个总结 a.h #include " ...

  10. SQL语言(一)

    设计表student如下