拥有许多小方法是否有助于JIT编译器进行优化?

编程入门 行业动态 更新时间:2024-10-28 15:20:59
本文介绍了拥有许多小方法是否有助于JIT编译器进行优化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

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

In a recent discussion about how to optimize some code, I was told that breaking code up into lots of small methods can significantly increase performance, because the JIT compiler doesn't like to optimize large methods.

我不确定这一点,因为看起来JIT编译器本身应该能够识别自包含的代码段,而不管它们是否采用自己的方法。

I wasn't sure about this since it seems that the JIT compiler should itself be able to identify self-contained segments of code, irrespective of whether they are in their own method or not.

任何人都可以确认或反驳这项索赔吗?

Can anyone confirm or refute this claim?

推荐答案

仅限Hotspot JIT内联小于某个(可配置)大小的方法。所以使用较小的方法允许更多的内联,这是好的。

The Hotspot JIT only inlines methods that are less than a certain (configurable) size. So using smaller methods allows more inlining, which is good.

请参阅此页。

编辑

详细说明:

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

示例(完整代码,如果您尝试使用相同的行号)

Example (full code to have the same line numbers if you try it)

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 和 m2 低于阈值 - 其他值可能会得到不同的输出。)

When running this code with the following JVM flags: -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:FreqInlineSize=50 -XX:MaxInlineSize=50 -XX:+PrintInlining (yes I have used values that prove my case: m is too big but both the refactored m and m2 are below the threshold - with other values you might get a different output).

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

You will see that m() and main() get compiled, but m() does not get inlined:

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:Prin tAssemblyOptions = intel ) - 它将如下所示:

You can also inspect the generated assembly to confirm that m is not inlined (I used these JVM flags: -XX:+PrintAssembly -XX:PrintAssemblyOptions=intel) - it will look like this:

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

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

If you refactor the code like this (I have extracted the if/else in a separate method):

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; }

您将看到以下编译操作:

You will see the following compilation actions:

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)

所以 m2 被内联到 m ,你会期望我们回到原来的情景。但是当 main 被编译时,它实际上是整个内容的内联。在汇编级别,这意味着您将不再找到任何 invokevirtual 指令。你会发现这样的行:

So m2 gets inlined into m, which you would expect so we are back to the original scenario. But when main gets compiled, it actually inlines the whole thing. At the assembly level, it means you won't find any invokevirtual instructions any more. You will find lines like this:

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

其中基本上常见的指令是共同的 。

where basically common instructions are "mutualised".

结论

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

I am not saying that this example is representative but it seems to prove a few points:

  • 使用更小的方法提高了代码的可读性
  • 更小的方法通常会内联,因此您很可能不会支付额外方法调用的成本(它将是性能中立的)
  • 使用较小的方法可能改进内联在某些情况下全局,如上例所示
  • using smaller method improves readability in your code
  • smaller methods will generally be inlined, so you will most likely not pay the cost of the extra method call (it will be performance neutral)
  • using smaller methods might improve inlining globally in some circumstances, as shown by the example above

最后:如果你的代码的一部分对性能非常重要考虑因素很重要,您应该检查JIT输出以微调您的代码,并重要地在之前和之后进行配置。

And finally: if a portion of your code is really critical for performance that these considerations matter, you should examine the JIT output to fine tune your code and importantly profile before and after.

更多推荐

拥有许多小方法是否有助于JIT编译器进行优化?

本文发布于:2023-11-07 09:18:19,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1566071.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:编译器   方法   JIT

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!