Fod*_*der 6 java optimization jvm variadic-functions
在vJUG24,其中一个主题是JVM性能.
幻灯片可以在这里找到.
他有一个例子:
static void log(Object... args) {
for(Object arg : args) {
System.out.println(arg);
}
}
Run Code Online (Sandbox Code Playgroud)
被称为通过(不能正确读取幻灯片,但它是相似的):
void doSomething() {
log("foo", 4, new Object());
}
Run Code Online (Sandbox Code Playgroud)
他说因为它是一种静态方法,所以可以通过内联它来优化它:
void doSomething() {
System.out.println("foo");
System.out.println(new Integer(4).toString());
System.out.println(new Object().toString());
}
Run Code Online (Sandbox Code Playgroud)
为什么log方法对于JVM进行此优化是静态的很重要?
演示文稿不是很精确,或者说你做得不对.
事实上,即使使用varargs ,JVM 也可以内联非静态方法.而且,Object[]在某些情况下它可以消除相应阵列的分配.不幸的是,当vararg方法使用for循环遍历数组时,它不会这样做.
我做了以下JMH基准来验证理论并使用GC profiler(-prof gc)运行它.
package bench;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.infra.Blackhole;
public class VarArgs {
@Benchmark
public void inlineNonStatic(Blackhole bh) {
inlineNonStaticVA(bh, "foo", 4, new Object());
}
@Benchmark
public void inlineStatic(Blackhole bh) {
inlineStaticVA(bh, "foo", 4, new Object());
}
@Benchmark
public void loopNonStatic(Blackhole bh) {
loopNonStaticVA(bh, "foo", 4, new Object());
}
@Benchmark
public void loopStatic(Blackhole bh) {
loopStaticVA(bh, "foo", 4, new Object());
}
public void inlineNonStaticVA(Blackhole bh, Object... args) {
if (args.length > 0) bh.consume(args[0]);
if (args.length > 1) bh.consume(args[1]);
if (args.length > 2) bh.consume(args[2]);
if (args.length > 3) bh.consume(args[3]);
}
public static void inlineStaticVA(Blackhole bh, Object... args) {
if (args.length > 0) bh.consume(args[0]);
if (args.length > 1) bh.consume(args[1]);
if (args.length > 2) bh.consume(args[2]);
if (args.length > 3) bh.consume(args[3]);
}
public void loopNonStaticVA(Blackhole bh, Object... args) {
for (Object arg : args) {
bh.consume(arg);
}
}
public static void loopStaticVA(Blackhole bh, Object... args) {
for (Object arg : args) {
bh.consume(arg);
}
}
}
Run Code Online (Sandbox Code Playgroud)
-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining 显示所有4个变体都成功内联到调用者:
@ 28 bench.VarArgs::inlineNonStaticVA (52 bytes) inline (hot)
@ 27 bench.VarArgs::inlineStaticVA (52 bytes) inline (hot)
@ 28 bench.VarArgs::loopNonStaticVA (35 bytes) inline (hot)
@ 27 bench.VarArgs::loopStaticVA (33 bytes) inline (hot)
Run Code Online (Sandbox Code Playgroud)
结果证实,调用静态方法与非静态方法之间没有性能差异.
Benchmark Mode Cnt Score Error Units
VarArgs.inlineNonStatic avgt 20 9,606 ± 0,076 ns/op
VarArgs.inlineStatic avgt 20 9,604 ± 0,040 ns/op
VarArgs.loopNonStatic avgt 20 14,188 ± 0,154 ns/op
VarArgs.loopStatic avgt 20 14,147 ± 0,059 ns/op
Run Code Online (Sandbox Code Playgroud)
但是,GC事件探查器指示Object[]为loop*方法分配了vararg 数组,但没有为inline*方法分配.
Benchmark Mode Cnt Score Error Units
VarArgs.inlineNonStatic:·gc.alloc.rate.norm avgt 20 16,000 ± 0,001 B/op
VarArgs.inlineStatic:·gc.alloc.rate.norm avgt 20 16,000 ± 0,001 B/op
VarArgs.loopNonStatic:·gc.alloc.rate.norm avgt 20 48,000 ± 0,001 B/op
VarArgs.loopStatic:·gc.alloc.rate.norm avgt 20 48,000 ± 0,001 B/op
Run Code Online (Sandbox Code Playgroud)
我想,最初的观点是静态方法总是单形的.但是,如果特定调用站点中没有太多实际接收器,JVM也可以内联多态方法.
| 归档时间: |
|
| 查看次数: |
165 次 |
| 最近记录: |