java - java接口方法内联
问题描述
我对来自 c++ 世界的 java 很陌生。我正在运行一些服务器代码,该代码运行一个方法 foo() ,该方法每秒被调用几百万次。这是对延迟敏感的代码,并且该方法在分析器中也显示为消耗进程总 CPU 使用量的 20%。
int foo_old() {
if (Float.isNan(this.x)) { // shows up in profiling
res = do some computation; // some floating point comparison, doesn't show up in profiling;
return res;
} else {
// Happens 99% of the time;
res = do something else; // some floating point comparison, doesn't show up in profiling;
return res;
}
}
有没有一种简单的方法可以测试我的方法 foo 是否会被内联?我可以从正在运行的服务器中的探查器堆栈跟踪信息中知道吗?
我通过尝试简化方法 foo() 尝试了一些优化。基本上在 foo 中有一个 float.isNan 检查,它也显示在 profiler 上,惊讶地发现 nan 检查速度较慢。相比其他一些布尔运算(小于、大于浮点比较)更快。
我尝试的一种方法是删除 nan check ,即因为我在编译时知道一个对象是否需要 nan check ,所以我尝试存储一个功能接口(成员变量)并分配这个功能接口 foo_old (具有 nan check)或 foo_optimized (不做nan检查)基于创建对象时已知的对象属性(在对象的构造函数中,我为此接口分配了正确的方法引用。
class A {
final FuncIf test; // Functional interface with same signature as foo_old, foo_new
public A(bool optimize) {
test = optimize ? this::foo_optimized : this::foo_old;
}
// same as the original foo mentioned above
int foo_old() {
...
}
// No nan check
int foo_optimized() {
res = do some computation;
return res;
}
}
现在,当我创建对象时,我知道在编译时间/对象构造时间使用哪个版本的 foo。所以我将接口变量分配给正确版本的 foo。部署后,我观察到延迟实际上增加了 < 10% 。尽管现在许多对象实际上将使用 foo 的优化版本。
是因为 foo 之前是直接方法调用,并且一旦我使用接口引用,调度虚拟 foo 的额外间接是我在延迟中看到的开销(接口方法调用的开销远大于 Nan 检查本身?? ) ? jvm编译器不能内联这个接口方法吗?
解决方案
唯一有根据的猜测是测量它的bytecode
. 为此使用javap
。基本上JVM
有两个编译器C1
和C2
; 两者都可以内联该方法。
JVM
内联时关心三个参数(嗯,这些是我知道的,我也知道还有很多):
-XX:MaxInlineSize (35 by default)
-XX:FreqInlineSize (325 by default)
-XX:MinInliningThreshold (250 by default)
如果你的方法调用小于MinInliningThreshold
(250),它遵守MaxInlineSize
规则,这意味着如果它小于 35 字节,它将被内联。如果它被调用的更多,那么它会服从FreqInlineSize
325 个字节(更多)。
您还可以做的是通过一些参数打印内联或不内联的内容:
-XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining
作为运行的结果,您可以看到如下消息:
callee is too large
这是由打印的C1
,它告诉您MaxInlineSize
该编译方法的超出范围。或者:
too big
超出C2
时由编译器打印。MaxInlineSize
或者 :
hot method too big
C2
超过时打印FreqInlineSize
。
推荐阅读
- sharepoint - 在 PowerApps 中查询超过 5k 的 SharePoint 列表,每个项目具有唯一权限
- javascript - 钩子和网络工作者
- angular - Angular 无法绑定到“产品”,因为它不是“应用产品卡”的已知属性
- javascript - JavaScript 仅显示 2 位小数而没有完整值
- sql - 分组数据的最高排名值
- rest - 需要微软合作伙伴中心 API 401 MFA
- netsuite - 通过 SuiteScript 在 NetSuite 中创建自定义记录类型
- c - 为什么 C 会说“字符”是未定义的”,即使我已经在它上面的结构中定义了它?
- android - 如何在 android 项目中从 gradle 调用 kotlin 函数?
- python - 如何修复有向图,使最顶层的父级始终是第一级?