拥有大量小方法是否有助于 JIT 编译器优化?

2023-12-28

在最近关于如何优化某些代码的讨论中,我被告知将代码分解为许多小方法可以显着提高性能,因为 JIT 编译器不喜欢优化大型方法。

我对此不确定,因为似乎 JIT 编译器本身应该能够识别独立的代码段,无论它们是否在自己的方法中。

谁能证实或反驳这一说法?


Hotspot JIT 仅内联小于特定(可配置)大小的方法。因此,使用较小的方法可以实现更多的内联,这很好。

请参阅上的各种内联选项这一页 http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html.


EDIT

详细说明一下:

  • 如果一个方法很小,它将被内联,因此几乎不会因为将代码拆分为小方法而受到惩罚。
  • 在某些情况下,拆分方法可能会导致更多内联。

Example(如果您尝试的话,完整的代码将具有相同的行号)

package javaapplication27;

public class TestInline {
    private int count = 0;

    public static void main(String[] args) throws Exception {
        TestInline t = new TestInline();
        int sum = 0;
        for (int i  = 0; i < 1000000; i++) {
            sum += t.m();
        }
        System.out.println(sum);
    }

    public int m() {
        int i = count;
        if (i % 10 == 0) {
            i += 1;
        } else if (i % 10 == 1) {
            i += 2;
        } else if (i % 10 == 2) {
            i += 3;
        }
        i += count;
        i *= count;
        i++;
        return i;
    }
}

使用以下 JVM 标志运行此代码时:-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:FreqInlineSize=50 -XX:MaxInlineSize=50 -XX:+PrintInlining(是的,我使用了证明我的情况的值:m太大了但是都重构了m and m2低于阈值 - 使用其他值您可能会得到不同的输出)。

你会看到m() and main()得到编译,但是m()没有内联:

 56    1             javaapplication27.TestInline::m (62 bytes)
 57    1 %           javaapplication27.TestInline::main @ 12 (53 bytes)
          @ 20   javaapplication27.TestInline::m (62 bytes)   too big

您还可以检查生成的程序集以确认m不是内联的(我使用了这些 JVM 标志:-XX:+PrintAssembly -XX:PrintAssemblyOptions=intel) - 它看起来像这样:

0x0000000002780624: int3   ;*invokevirtual m
                           ; - javaapplication27.TestInline::main@20 (line 10)

如果你像这样重构代码(我已经在单独的方法中提取了 if/else):

public int m() {
    int i = count;
    i = m2(i);
    i += count;
    i *= count;
    i++;
    return i;
}

public int m2(int i) {
    if (i % 10 == 0) {
        i += 1;
    } else if (i % 10 == 1) {
        i += 2;
    } else if (i % 10 == 2) {
        i += 3;
    }
    return i;
}

您将看到以下编译操作:

 60    1             javaapplication27.TestInline::m (30 bytes)
 60    2             javaapplication27.TestInline::m2 (40 bytes)
            @ 7   javaapplication27.TestInline::m2 (40 bytes)   inline (hot)
 63    1 %           javaapplication27.TestInline::main @ 12 (53 bytes)
            @ 20   javaapplication27.TestInline::m (30 bytes)   inline (hot)
            @ 7   javaapplication27.TestInline::m2 (40 bytes)   inline (hot)

So m2被内联到m,这是你所期望的,所以我们回到了原来的场景。但当main被编译后,它实际上内联了整个内容。在程序集级别,这意味着您找不到任何invokevirtual不再有说明。你会发现这样的行:

 0x00000000026d0121: add    ecx,edi   ;*iinc
                                      ; - javaapplication27.TestInline::m2@7 (line 33)
                                      ; - javaapplication27.TestInline::m@7 (line 24)
                                      ; - javaapplication27.TestInline::main@20 (line 10)

基本上通用指令是“相互化的”。

结论

我并不是说这个例子具有代表性,但它似乎证明了几点:

  • 使用更小的方法可以提高代码的可读性
  • 较小的方法通常会被内联,因此您很可能不会支付额外方法调用的成本(这将是性能中性的)
  • 使用更小的方法might在某些情况下改进全局内联,如上例所示

最后:如果代码的一部分对于这些考虑因素的性能确实至关重要,那么您应该检查 JIT 输出以微调您的代码,并且重要的是在前后进行分析。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

拥有大量小方法是否有助于 JIT 编译器优化? 的相关文章

随机推荐

  • FIELDDATA 数据太大

    我打开 kibana 并进行搜索 然后收到分片失败的错误 我查看了 elasticsearch log 文件 看到了这个错误 org elasticsearch common breaker CircuitBreakingException
  • 使用 gnuplot 的向量场

    如何绘制矢量场 其中每个点 x y 的方向由下式给出tangent alpha f x y 据我所知 gnuplot 只能在从文件读取数据时绘制向量场 您的文件必须有 4 列 x y deltax 和 delta y 然后 gnuplot
  • Unity aab 不符合 Google Play 64 位要求

    我有一个 Unity 项目 正在从 APK 切换到 AAB 应用程序包 以前 当我将其构建为 APK 时 Google Play 控制台告诉我该 APK 兼容 64 位 现在我正在构建 aab 我收到警告 此版本不符合 Google Pla
  • 有趣的 SQL 连接日期之间的日期

    首先 感谢任何帮助我解决这个问题的人 我使用的是 SQL 2005 但如果 05 中没有可用的解决方案 可以使用 2008 我有一行数据 如下所示 select from mySPtable myPK Area RequestType St
  • 可靠地显示 matplotlib(0.99 到 1.3.1)数字而不会阻塞

    有没有办法在 Python 2 65 Matplotlib 0 99 中显示 pyplot 图 而不锁定其他所有内容 我有一个带有 Pmw GUI 的程序 在 Python 2 75 和 Matplotlib 1 3 1 上运行 在 Win
  • AppCertDlls:病毒导致 Win32 上的进程创建速度减慢

    大约两个月来 我在 Windows XP Home SP3 上遭受了严重的进程创建惩罚 这个问题在创建大量进程的任务中最为明显且烦人 例如 shell 脚本 顺便说一句 Cygwin 上的 bash 脚本 Makefile 或解压 IzPa
  • 增强导入的打字稿界面

    我正在使用一个包 ko 组件路由器 https github com Profiscience ko component router 具有以下 简明 类型定义 索引 d ts export IContext Context from co
  • Angular 2 中 JavaScript 堆内存不足

    我正在使用 Angular CLI 请检查我的 CLI 信息 angular cli 1 2 1 node 6 10 0 os win32 x64 angular animations 4 1 1 angular common 4 0 0
  • EF 7:如何加载一对多关系中的相关实体

    我有以下代码 为什么我的导航属性 课程中的要求和要求中的课程 为空 public class Course AbsEntity Key public string Title get set public string Term get s
  • 问:R 中的 KNN——奇怪的行为

    有谁知道为什么下面的 KNN R 代码对不同的种子给出不同的预测 这很奇怪 因为 Kpost library class set seed 642002713 m 20 n 1000 from 2 30 to from train matr
  • 如何使用Python在Telegram机器人中发送表情符号?

    我正在处理一个小项目 我决定添加表情符号以使视觉效果更好一点 但我无法发送它 我尝试过像 U000203C 这样的 Unicode 甚至尝试复制表情符号并粘贴它 但仍然无法做到 有什么办法可以发送表情符号吗 Unicode exchange
  • 如何打开 VS Code 并通过 CLI 将命令传递到集成终端

    我想知道如何使用code命令打开VS Code与综合终端 https code visualstudio com docs editor integrated terminal启动时运行一些我直接传递到集成终端的命令 现在我需要采取一些行动
  • boost::ref 没有发生匹配的调用错误,但 std::ref 则没有发生匹配的调用错误

    我编写了一些代码 它使用函子和ref and bind模板来自boost or std 对于 C 11 命名空间 我正在使用一个 define之间切换boost and std 命名空间 我使用的是 boost 版本 1 53 我的编译命令
  • Pyinstaller 可执行文件导入 torchvision 失败

    这是我的main py import torchvision input Press key 它在命令行中正确运行 python main py 我需要一个适用于 Windows 的可执行文件 所以我做了 pyinstaller main
  • 更改asp图表图例标签宽度

    Aspx
  • Fancybox2:修改对多个画廊的呼吁

    我正在生成一个 HTML 页面 其中包含来自 MySQL 数据库中保存的信息的多个画廊 我需要修改 Fancybox2 调用 如下所示 document ready function a rel gall24 a rel gall30 et
  • 显示 (head .unit ) = Agda 中的 head

    我试图证明 Agda 中的一个简单引理 我认为这是正确的 如果向量有两个以上元素 则取其head继采取init与取其相同head立即地 我将其表述如下 lem headInit l xs Vec suc suc l gt head init
  • 在 Doctrine 中,如何忽略更新架构命令中的特定列?

    我有我的映射实体 named Product 只有两列 id and name 如果我手动添加另一列 即stock qty直接使用SQL语句 架构更新工具将远程它 当然 如何防止 Doctrine 删除我的自定义列 而不是映射到我的实体 相
  • 如何在 HTTP 查询字符串中发送 NULL?

    我正在开发一个 API 它可以接受主要三种数据类型作为查询字符串参数的值 boolean string numeric integer or float 默认情况下 所有内容都以字符串检索 我认为没有办法解决这个问题 但参数配置了类型 以便
  • 拥有大量小方法是否有助于 JIT 编译器优化?

    在最近关于如何优化某些代码的讨论中 我被告知将代码分解为许多小方法可以显着提高性能 因为 JIT 编译器不喜欢优化大型方法 我对此不确定 因为似乎 JIT 编译器本身应该能够识别独立的代码段 无论它们是否在自己的方法中 谁能证实或反驳这一说