现代 JVM 可以不同地优化相同 class 的不同实例吗?
can moderm JVMs optimize different instances of the same class differently?
说我有 2 个相同的 class 实例,但它们的行为不同(遵循不同的代码路径)基于构建时设置的最终布尔字段。所以像:
public class Foo {
private final boolean flag;
public Foo(boolean flagValue) {
this.flag = flagValue;
}
public void f() {
if (flag) {
doSomething();
} else {
doSomethingElse();
}
}
}
Foo
的 2 个实例具有不同的 flag
值在理论上可以由 2 个不同的程序集支持,从而消除 if 的成本(对于人为的例子,它是最简单的一个我可以想出)。
所以我的问题是 - 有任何 JVM 真的这样做吗?还是单个 class 总是由单个程序集支持?
以下适用于热点,其他 JVM 可能会应用不同的优化。
如果这些实例依次分配给 static final
字段,然后被其他代码引用并且 VM 以 -XX:+TrustFinalNonStaticFields
启动,那么这些实例可以参与常量折叠和内联 CONSTANT.f()
可以导致不同的分支被淘汰。
特权代码可用的另一种方法是通过 sun.misc.Unsafe.defineAnonymousClass(Class<?>, byte[], Object[])
创建匿名 classes 而不是实例,并为每个 class 修补一个 class 常量,但最终也是必须通过 class 常量引用才能对优化产生任何影响。
是的,JVM 执行这种形式的优化。在您的情况下,这将是 inlining and adaptive optimization 作为一个始终为真的值的结果。考虑以下代码:
Foo foo = new Foo(true);
foo.f();
为 HotSpot 证明 Foo
始终是 Foo
在 f
的调用站点上的实际实例是微不足道的,它允许 VM 简单地复制粘贴代码的方法,从而消除了虚拟分派。内联后,例子缩减为:
Foo foo = new Foo(true);
if (foo.flag) {
doSomething();
} else {
doSomethingElse();
}
这又一次允许将代码减少为:
Foo foo = new Foo(true);
foo.doSomething();
是否可以应用优化因此取决于 foo 调用站点的单态性和 flag
在该调用站点的稳定性。 (VM 为此类模式描述您的方法。)VM 能够预测您的程序的结果越少,应用的优化就越少。
如果示例像上面的代码一样简单,JIT 可能还会擦除对象分配并简单地调用 doSomething
。此外,对于字段值可以被证明为 true
的简单示例情况,VM 甚至不需要自适应优化,而只是应用上述优化。有一个名为 JITWatch 的很棒的工具,可让您查看代码是如何优化的。
说我有 2 个相同的 class 实例,但它们的行为不同(遵循不同的代码路径)基于构建时设置的最终布尔字段。所以像:
public class Foo {
private final boolean flag;
public Foo(boolean flagValue) {
this.flag = flagValue;
}
public void f() {
if (flag) {
doSomething();
} else {
doSomethingElse();
}
}
}
Foo
的 2 个实例具有不同的 flag
值在理论上可以由 2 个不同的程序集支持,从而消除 if 的成本(对于人为的例子,它是最简单的一个我可以想出)。
所以我的问题是 - 有任何 JVM 真的这样做吗?还是单个 class 总是由单个程序集支持?
以下适用于热点,其他 JVM 可能会应用不同的优化。
如果这些实例依次分配给 static final
字段,然后被其他代码引用并且 VM 以 -XX:+TrustFinalNonStaticFields
启动,那么这些实例可以参与常量折叠和内联 CONSTANT.f()
可以导致不同的分支被淘汰。
特权代码可用的另一种方法是通过 sun.misc.Unsafe.defineAnonymousClass(Class<?>, byte[], Object[])
创建匿名 classes 而不是实例,并为每个 class 修补一个 class 常量,但最终也是必须通过 class 常量引用才能对优化产生任何影响。
是的,JVM 执行这种形式的优化。在您的情况下,这将是 inlining and adaptive optimization 作为一个始终为真的值的结果。考虑以下代码:
Foo foo = new Foo(true);
foo.f();
为 HotSpot 证明 Foo
始终是 Foo
在 f
的调用站点上的实际实例是微不足道的,它允许 VM 简单地复制粘贴代码的方法,从而消除了虚拟分派。内联后,例子缩减为:
Foo foo = new Foo(true);
if (foo.flag) {
doSomething();
} else {
doSomethingElse();
}
这又一次允许将代码减少为:
Foo foo = new Foo(true);
foo.doSomething();
是否可以应用优化因此取决于 foo 调用站点的单态性和 flag
在该调用站点的稳定性。 (VM 为此类模式描述您的方法。)VM 能够预测您的程序的结果越少,应用的优化就越少。
如果示例像上面的代码一样简单,JIT 可能还会擦除对象分配并简单地调用 doSomething
。此外,对于字段值可以被证明为 true
的简单示例情况,VM 甚至不需要自适应优化,而只是应用上述优化。有一个名为 JITWatch 的很棒的工具,可让您查看代码是如何优化的。