多维数组是C#中的一种数据结构。使用多维数组时,不同维度的数组元素在内存中的布局形式是怎样的呢?
下面这一段代码将告诉我们C#中多维数组的内存布局:
const int size = 10000;
byte[,] a = new byte[size, size];
unsafe
{
fixed (byte* ptr00 = &a[0, 0], ptr01 = &a[0, 1], ptr10 = &a[1, 0])
{
Console.WriteLine("&a[0,0]={0}", (long)ptr00);
Console.WriteLine("&a[0,1]={0}", (long)ptr01);
Console.WriteLine("&a[1,0]={0}", (long)ptr10);
}
}
在.NET Core 2.1版本中,输出结果为:
&a[0,0]=1549210047680
&a[0,1]=1549210047681
&a[1,0]=1549210057680
可以看到,a[0,0]的地址与a[0,1]相邻,却与a[1,0]不相邻。这说明C#多维数组的最后一个维度是连续排列的。
基于这个结论,理论上遍历一个数组的时候,应该是将最后一个维度作为最内层循环性能较好。我们编写一段代码,观察写入一个二维数组时,两重循环的顺序对执行时间的影响:
Stopwatch sw = new Stopwatch();
sw.Reset();
sw.Start();
for (int i = 0; i < size; ++i)
{
for (int j = 0; j < size; ++j)
{
a[i, j] = (byte)(i + j);
}
}
sw.Stop();
Console.WriteLine(sw.Elapsed);
sw.Reset();
sw.Start();
for (int j = 0; j < size; ++j)
{
for (int i = 0; i < size; ++i)
{
a[i, j] = (byte)(i + j);
}
}
sw.Stop();
Console.WriteLine(sw.Elapsed);
// 重复上述代码一遍以减少先后顺序带来的影响
输出结果为:
00:00:01.6993174
00:00:02.5070039
00:00:01.1089673
00:00:02.2817417
这印证了我们刚才得出的结论。
综上所述,C#的多维数组最后一维在内存上是连续排列的,为了提高性能,遍历多维数组时应尽量将最后一个维度放在最内层循环。
留言
有想法?请给我们留言!您的留言不会直接显示在网站内。