有一些简单的代码
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());
Run Code Online (Sandbox Code Playgroud)
我的核心2组合需要大约3秒钟.如果我将t1中的索引更改为tmpInt [4],则需要约5.5秒.
无论如何,第一个缓存行在索引4处结束.由于缓存行是64字节而5个int32只是20个字节,这意味着在实际数组之前有44个字节的元数据和/或填充.
我测试的另一组值,其中5和21.5和21需要~3秒,但5和20需要~5.5秒,但这是因为索引20与索引5共享相同的缓存行,因为它们在相同的间隔内64个字节.
所以我的问题是,.Net在数组之前预留了多少数据并且这个数量在32位和64位系统之间变化了吗?
谢谢 :-)
当 CPU 尝试加载您的数组并遇到缓存未命中时,它会获取包含您的数组的内存块,但不一定从它开始。.NET 不保证您的数组将缓存对齐。
为了回答您的问题,44 字节的填充主要是来自相关页面的其他数据,这些数据恰好位于同一缓存行中。
编辑:http : //msdn.microsoft.com/en-us/magazine/cc163791.aspx似乎表明一个数组有 16 个字节的额外存储空间。4 个字节是同步块索引,4 个字节用于类型句柄元数据,其余的是对象本身。
作为附带评论,很难确切地说错误共享是造成您在这里延迟的原因。这可能是给定的时间,但您应该使用一个好的分析器来检查缓存未命中率。如果它在您给定的情况下跳得很高,您可以非常确定您正在看到虚假共享。
| 归档时间: |
|
| 查看次数: |
763 次 |
| 最近记录: |