把Array说透(续一)
1. 写在前面的
在前文中,我主要介绍了数组的一些相关知识,希望加深各位对Array的理解,不过,看过Ivony…同学的回复,我发觉自己离说透还有很大的距离,于是就有了下面的文章。在本文中,我也主要来围绕Ivony…同学提出的几点问题来作以说明,问题如下:
A、数组在托管堆内部是怎么存放的?数组元素的位置是连续的么?
B、非零基数组可以和零基数组转换么?
C、int[]与System.Array的关系到底是同一类型?还是基类与派生类的关系?
D、ldelem不检查下标越界么?
E、多维数组可以和零基数组转换么?
F、Array.Copy和CopyTo与手动拷贝性能有多大差距?
G、数组的协变是怎么做到的?
H、数组是如何实现泛型接口(如IList<T>)的?
I、多维数组每一维度长度必须相等么?必须零基么?
J、数组的Length属性到底指示的是什么?
2. 数组内存详解
在这里,我们依然把数组分为零基数组和非零基数组来讨论。
首先来看零基数组的内存分配,废话少说,我们先来看测试代码:
static unsafe void Main(string[] args) {int[] intArr = new int[3];intArr[0] = 1;intArr[1] = 2;intArr[2] = 3; }
代码本身很简单,接下来单步执行向下看,首先我们来查看一下源代码的汇编代码:
int[] intArr = new int[3]; 00000035 mov edx,3 0000003a mov ecx,61CD4192h 0000003f call FFFB2140 00000044 mov dword ptr [ebp-44h],eax 00000047 mov eax,dword ptr [ebp-44h] 0000004a mov dword ptr [ebp-40h],eax intArr[0] = 1; 0000004d mov eax,dword ptr [ebp-40h] 00000050 cmp dword ptr [eax+4],0 00000054 ja 0000005B 00000056 call 624B6B29 0000005b mov dword ptr [eax+8],1 intArr[1] = 2; 00000062 mov eax,dword ptr [ebp-40h] 00000065 cmp dword ptr [eax+4],1 00000069 ja 00000070 0000006b call 624B6B29 00000070 mov dword ptr [eax+0Ch],2 intArr[2] = 3; 00000077 mov eax,dword ptr [ebp-40h] 0000007a cmp dword ptr [eax+4],2 0000007e ja 00000085 00000080 call 624B6B29 00000085 mov dword ptr [eax+10h],3 }
在这里,我们就可以清晰地发现,在0x0000005b,0x00000070和0x00000085中,mov操作的目标地址之间是相隔4个Bytes的,也就是一个整数位。接下来我们来进一步证实。
当我们为数组分配过内存地址后,打开即使窗口查看数组所在的内存地址。
接下来打开内存窗口还查看0x015cc790内存块的数据:
以上是对数组赋值前的情况,赋值后的内存数据如下:
在这里可以更清晰地看出,数组元素之间差的正好是4个Bytes,也就是一个整数位。由此,我们可以得出结论。零基数组的元素在内存中是连续排布的。
接下来我们来看一下非零基数组:
由于空间所限,过程如上,就不再发,截图证明:
总之,当我们在托管堆中为数组分配内存时,数组占据一段连续的内存空间。
我们知道,当我们在托管堆中初始化一个对象时,每个对象都需要维护一个指针,该指针的作用是指向下一块空闲内存空间,由于对数组的操作经常是循环遍历等操作,这样如果把数组分配到一个连续的内存空间有一下两个好处:
A. 减少内存碎片
B. 节省内存,不需要维护指针
C. 基地址不需要发生变化,只需要改变偏移量即可,在一定程度上也提高了访问的效率。
接下来,我们还需要来补充一下数组在栈上分配内存的情况:
还记得上文中提到的这个关键字吧,stackalloc,就是他了。补充一下,在上文的回复中,有人问到说栈空间上分配的内存是不是也被垃圾回收器回收?这里的栈空间和C语言中的栈一样,没有垃圾回收器,每个变量都有他自己的作用域,当出了作用域后,变量自动销毁,具体的函数执行过程,请参看《深入理解计算机系统》。
3. 再论零基数组和非零基数组
我们先来看这样一段代码:
static void Main(string[] args) {int[,] intArr = (int[,])(Array.CreateInstance(typeof(Int32), new int[] { 3,4 }, new int[] { 1,1 }));intArr[2, 3] = 1; }
这段代码没有问题,我们将Array显式地转换成了强类型的二维数组,然后直接访问索引对其复制。
但是我们知道,对弱类型的Array而言,我们不能通过其下标访问他的元素,而只能通过SetValue和GetValue来获得值,但是我们看到SetValue和GetValue访问和设置的值的类型都是Object,这就意味着我们需要对其进行一次装箱或者拆箱。那么我们有没有办法也生成一个强类型的非零基数组呢?
在上文中,我们提到过,.NET Framework的几种数组类型:
一维零基数组:System.Int32[]。一维非零基数组:System.Int32[*]。多维数组:System.Int32[,]。
那么也就是说,我们是否能通过这样的代码来把Array转换成一维非零基数组呢?
static void Main(string[] args) {int[*] intArr = (int[*])(Array.CreateInstance(typeof(Int32), new int[] { 3}, new int[] { 1 })); }
事实证明是错误的。在CLR via C#中Jeffery有这样一段话:
“C# does not allow you to declare a variable of type string[*],and therefore it is not possible to user C# syntax to access a single-dimensional ,non-zero-based array.”
这段话翻译成中文的意思就是:C#不允许声明一个string[*]类型的变量,因此,我们能够使用C#语法来访问一个非零基一维数组。
通过以上的解释,我们也许又额外明白了一点,Array究竟是数组类型,还是数组类型的基类?
通过上面的一些代码,我们不妨又把数组重新分类为“强类型数组”和“弱类型数组”。而Array就属于弱类型数组。为什么Array是所有数组类型的基类,我没想出办法来如何证明,只是看到Jeffery说了这样一句话:
“All Arrays are Implicitly Derived from System.Array”。
我想这句话可以说明问题了,不过还是希望各位大侠指点如果证明这一点。
未完持续…………
转载于:https://www.cnblogs.com/kym/archive/2009/10/09/1579958.html
把Array说透(续一)相关推荐
- 老男孩上海校区Python面试题
python面试题 第一章:python基础 数据类型: 1 字典: 1.1 现有字典 dict={'a':24,'g':52,'i':12,'k':33}请按字典中的 value 值进行排序? 1. ...
- atl offsetofclass
首页 | 互联网 | IT动态 | IT培训 | Cisco | Windows | Linux | Java | .Net | Oracle | 软件测试 | C/C++ | 嵌入式 | 存储世界服 ...
- iPhone13下周三发布,提前看剧透:刘海缩小、120Hz高刷屏、Mini又续一年…
梦晨 发自 凹非寺 量子位 报道 | 公众号 QbitAI 不少人在期盼着iPhone13,毕竟是"十三香". 到目前为止,苹果的动作和网上的"剧透"那是一模一 ...
- 十二之续、快速排序算法的深入分析
十二之续.快速排序算法的深入分析 作者:July 二零一一年二月二十七日 -------------------------- 前言 一.快速排序最初的版本 二.Hoare版本的具体分析 三.Ho ...
- java array 元素的位置_Java常见面试题 非常实用「个人经验」
Java 容器都有哪些 Collection 的子类 List.Set List 的子类 ArrayList.LinkedList等 Set 的子类 HashSet.TreeSet等 Map 的子类 ...
- 面向对象程序设计_面向对象的程序设计(续)
写在前面:这里是续之前的那篇文章,同样源于本人的个人博客,在知乎为了一个备份 这里是7-10章 Chapter 7: Arrays 数组 记得在C语言里面,也有提到过数组这个概念 记得RT也说过这玩意 ...
- 《编程珠玑(续)(修订版)》—第2章2.1节Awk中的关联数组
本节书摘来自异步社区<编程珠玑(续)(修订版)>一书中的第2章,第2.1节Awk中的关联数组,作者[美]Jon Bentley,更多章节内容可以访问云栖社区"异步社区" ...
- js array 删除指定元素_Array 原型方法源码实现解密
作者:木易杨 引言 今天这篇文章主要看看 ECMA-262 规范中是如何定义这些方法的,并且在看完规范后我们用 JS 模拟实现下,透过源码探索一些底层的知识,希望本文对你有所帮助. Array.pro ...
- 通过脚本下派WsusAgent3.0.exe(续)
在http://yangye.blog.51cto.com/922715/200444这篇文章中我提到过使用脚本结合调用runas命令来给客户端安装exe文件.如果做过测试的人会发现,这个脚本并不是很 ...
最新文章
- 规格表管理之删除规格表数据
- R语言jitter函数为数据添加噪声(noise)扰动信息实战
- Android Linux自带iptables配置IP访问规则
- linux开发常用脚本,记录自己常用的一些 Linux Shell 脚本
- CVPR 2018 MCCT:《Multi-Cue Correlation Filters for Roubust Visual Tracking》论文笔记
- centos 卸载自带的 java
- IUnknown接口QueryInterface函数介绍
- c iostream.源码_通达信《K线上画趋势线预警》精选指标(附源码)
- 表单提交数据丢失的问题
- php exec执行多条命令,小技巧:在PHP中调用多条shell指令
- 我要做 Android 之面笔试
- 机器人总动员中的小草_机器人总动员观后感(精选4篇)
- 交通灯控制系统的设计
- Unity 粒子特效 之 LogoEffect ParticleSystem 文字图片logo粒子特效
- 【空气质量数据分析专题二】数据获取及预处理
- 用EXCEL宏编写坐标转换
- 2021年低压电工及低压电工证考试
- 【android学习之十六】——特色功能1:GoogleMap手机地图
- 业务元数据管理——洞悉数据背后的业务含义
- 腾讯财报:2018年Q3腾讯净利润197.1亿元 同比增长15%