微基准和热路径

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

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 63w+ 字,讲解图 2808+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2200+ 小伙伴加入学习 ,欢迎点击围观

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

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

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

相关文章