最近,我在这里读到了关于jvm优化的文章,非常棒,
但我有一个优化问题,即空检查消除(或不常见的陷阱)
求和空校验消除 if (obj == null) ...
希望是最好的,而如果遇到分段错误,它会重新编译代码,这一次包括被忽略的部分 if (obj == null) ...
.
我的问题是,鉴于:
bool foo(MyClass obj)
{
if(obj == null)
return false;
m_someVar++;
obj.doSomething(m_someVar);
}
因为取消了空检查,并且只在 m_someVar++
.
foo会执行吗 m_someVar++
一个额外的时间c将为空?
编辑:
对于这种优化的实现,是否有更深入的解释来源,它解释了这种优化如何保持代码的语义相同?
谢谢
2条答案
按热度按时间0md85ypi1#
有许多可能避免这个问题:延迟或撤消增量已经在评论中提到。jvm有一大堆技巧,其中一些适用于:
什么时候
obj.doSomething(m_someVar)
是非虚拟方法调用(a)private
或者final
方法或从不重写的方法),则可能需要显式的null检查(),因为没有segv,但必须在调用之前抛出npe。我假设这个方法不是内联的,否则这个分析应该在内联之后应用。什么时候
obj.doSomething(m_someVar)
是一个虚拟方法调用,那么您必须执行“方法分派”,例如obj.getClass().getPointerToMethod("doSomething(int)")
以确定要调用的具体方法。我写了“像这样的东西”,因为这样做是非常耗时的,并得到尽可能多的优化。这个分派可以移动到增量的上方,它本身会抛出一个npe,如果obj
碰巧是null
.如果你运气好的话,派遣人员可能会
if (obj.getClass() != MyClass.class) uncommon_trap();
,这是最简单的情况(称为“单态调用站点”),但即使这样也涉及到解引用obj
你又一次得到了npenull
.()空检查可能看起来像
obj.getClass()
在汇编程序中,它是从相对于obj
指针。什么时候obj == null
然后出现一个未Map的页面。nxowjjhe2#
它认为您误解了空检查消除实际上是什么。
实际上,它是关于消除(例如)在示例上调用方法时隐式的空检查。
在您的示例中,显式
if(obj == null)
不会被淘汰。这将(正如您所观察到的)改变程序的行为。消除空检查将是不正确的优化。但是,在
HERE
在以下方面:因为jit编译器应该能够推断出
obj
在代码到达该点时始终为非空(不过,这是另一种空检查优化。)对于这个优化的实现是否有更深入的解释。。。
我不这么认为。至少,没有什么是确定的(除非计算jit编译器源代码中可能出现的注解!)
未指定jit优化器行为。只要不违反jls中定义的java语义,它基本上可以做任何事情。
... 这解释了这种优化是如何保持代码语义相同的?
正如我所解释的,您所阅读的乐观空检查消除优化不适用于您的示例(这会使代码按照jls的要求表现不正确。)