我正在做一些工作来重构一段复杂的代码,我有一段内存被分配,然后通过结构指针访问。这段代码被调用了很多,所以我想知道持有一个已经转换为正确结构指针的指针与对象中另一个指针的成本之间的权衡。
请注意,这些是 经常 创建并 经常 使用的对象。这些 不是 您通常需要担心的事情。因为我不确定,所以我决定对此进行测试。我使用 benchmarkdotnet 这样做:
public struct fooheader
{
public long pagenumber;
public int size;
}
[benchmarktask(platform: benchmarkplatform.x86,
jitversion: benchmarkjitversion.legacyjit)]
[benchmarktask(platform: benchmarkplatform.x64,
jitversion: benchmarkjitversion.legacyjit)]
[benchmarktask(platform: benchmarkplatform.x64,
jitversion: benchmarkjitversion.ryujit)]
public unsafe class tocastornottocast
{
byte* p;
fooheader* h;
public tocastornottocast()
{
p = (byte*)marshal.allochglobal(1024);
h = (fooheader*)p;
}
[benchmark]
public void nocast()
{
h->pagenumber++;
}
[benchmark]
public void cast()
{
((fooheader*)p)->pagenumber++;
}
[benchmark]
public void directcastarray()
{
((long*)p)[0]++;
}
[benchmark]
public void directcastptr()
{
(*(long*)p)++;
}
}
最后两个测试几乎只是为了进行比较,因为如果需要,我会手动计算内存偏移量,但我怀疑是否需要这些。
benchmarkdotnet 的一个缺点是实际运行这些测试需要 很 长时间。我会为你省去悬念,这是结果:
老实说,我预计 nocast 方法会更快。但是 cast 方法始终(非常轻微)是最快的方法。这是令人惊讶的。
这是生成的 il:
汇编代码的区别是:
请注意,我不是 100% 确定汇编代码。我从 vs 的反汇编窗口中得到它,它可能改变了实际发生的事情。
所以我不太确定为什么会有所不同,这确实是一个 很小的 差异。但它在那里。