微基准和热路径

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

我正在做一些工作来重构一段复杂的代码,我有一段内存被分配,然后通过结构指针访问。这段代码被调用了很多,所以我想知道持有一个已经转换为正确结构指针的指针与对象中另一个指针的成本之间的权衡。

请注意,这些是 经常 创建并 经常 使用的对象。这些 不是 您通常需要担心的事情。因为我不确定,所以我决定对此进行测试。我使用 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 的反汇编窗口中得到它,它可能改变了实际发生的事情。

所以我不太确定为什么会有所不同,这确实是一个 很小的 差异。但它在那里。