数组元数据问题(缓存行)

时间:2010-12-09 21:24:24

标签: c# .net

获得了一些简单的代码

Int32[] tmpInt = new Int32[32];

            long lStart = DateTime.Now.Ticks;


            Thread t1 = new Thread(new ThreadStart(delegate()
            {
                for (Int32 i = 0; i < 100000000; i++)
                    Interlocked.Increment(ref tmpInt[5]);
            }));

            Thread t2 = new Thread(new ThreadStart(delegate()
            {
                for (Int32 i = 0; i < 100000000; i++)
                    Interlocked.Increment(ref tmpInt[20]);
            }));


            t1.Start();
            t2.Start();

            t1.Join();
            t2.Join();

            Console.WriteLine(((DateTime.Now.Ticks - lStart)/10000).ToString());

我的核心2组合需要大约3秒钟。如果我将t1中的索引更改为tmpInt [4],则需要约5.5秒。

无论如何,第一个缓存行在索引4处结束。由于缓存行是64字节而5个int32s只有20个字节,这意味着在实际数组之前有44个字节的元数据和/或填充。

我测试的另一组值,其中5和21.5和21需要~3秒,但5和20需要~5.5秒,但这是因为索引20与索引5共享相同的缓存行,因为它们是间隔的在相同的64个字节内。

所以我的问题是,.Net在数组之前预留了多少数据,这个数量在32位和64位系统之间是否会发生变化?

谢谢: - )

2 个答案:

答案 0 :(得分:4)

当CPU尝试加载您的阵列并且遇到缓存未命中时,它会获取包含您的阵列的内存块,但不一定是STARTING。 .NET不保证您的数组将与缓存对齐。

要回答您的问题,44个字节的填充主要是来自关联页面的其他数据,这些数据恰好位于同一个缓存行中。

编辑http://msdn.microsoft.com/en-us/magazine/cc163791.aspx似乎表明数组有16个字节的额外存储空间。 4个字节是同步块索引,4个字节用于类型句柄元数据,其余的是对象本身。

作为一个评论,很难确切地说,错误分享是造成你的延迟的原因。可能会给出时间,但你应该使用一个好的分析器来检查缓存未命中率。如果它因你的情况而跳得很高,你可以非常肯定你在游戏中看到了虚假分享。

答案 1 :(得分:0)

除了答案: https://stackoverflow.com/a/1589806/543814

我的测试表明我期望的是32位[64位]:

  • 同步块:4B [8B]
  • 数组类型指针:4B [8B]
  • 阵列大小:4B [4B]
  • 元素类型指针:4B [8B](仅参考数组

总之,有4种可能性:

12 bytes (32-bit value array)
16 bytes (32-bit reference array)
20 bytes (64-bit value array)
28 bytes (64-bit reference array)

我过去遗漏的东西:在具有项目设置的64位计算机上,更喜欢32位&#39;启用(默认), 32位适用!