问题描述
假设我的代码如下:
log.info("Now the amount" + amount + " seems a bit high")
,我将用虚拟实现替换日志方法:
class Logger { ... public void info() {} }
优化器是否会内联,如果未检测到副作用,则删除死亡代码会删除参数构造吗?
推荐答案
我猜想编译器(Javac)不会,但是公正的编译器很可能会.
为了使其工作,它必须能够扣除您用于生成参数的任何指令都没有副作用.它应该能够为字符串的特殊情况做到这一点,但可能不能用于其他方法.
可以肯定的是,制作一个小型基准,将其与Jesper建议和看到的代码进行比较,以更快的速度或同样快.
另请参见: http://http://wwwwww .ibm.com/developerworks/java/library/j-jtp12214/index.html#3.0
其他推荐答案
重要的答案是:它可能会做.
我认为您不应该依靠来依靠优化者的任何特定行为.如果您的代码在没有优化的情况下快速运行,那么您可能会或可能不会提高性能,但是好消息是,无论如何,您的解决方案都可以.如果不优化的性能是可怕的,那不是一个好的解决方案.
依靠优化器的问题是,您正在设置自己符合您不知道的隐形合同. Hotspot在其他JDK/JRE版本中的性能会有所不同,因此不能保证仅仅因为它在您的确切JVM上运行良好,它在其他地方都可以正常运行.但是除此之外,发生的确切优化 May 取决于环境问题,例如自由堆的量,机器上的内核量等.
和甚至如果您设法确认它在您的情况下正常工作,那么您刚刚使您的代码库变得非常不稳定.我知道,热点确实取决于加载和用于非决赛类的子类的数量的优化/inlinings之一.如果您开始使用另一个库/模块,该图书馆/模块加载了第二个实现log - bang,则优化将变得解开,并且性能再次变得可怕.祝你好运,弄清楚如何在您的类路径上添加第三方库来敬酒您的应用程序的内部性能...
无论如何,我认为您不问真实问题.在您描述的情况下,更好的解决方案不是更改info方法的实现,而是更改对NO-OPS的调用(即对它们进行评论).如果您想一次在整个课程中进行此操作, compile Time ,您可以使用类型的IFDEF SO:
public class Log { public static final boolean USE_INFO = true; public void info() { ... } ... }
,然后在您的班级中:
if (Log.USE_INFO) { log.info("Now the amount" + amount + " seems a bit high"); }
现在,编译器(Javac,而不是热点)可以看到布尔条件是恒定的,并且在编译时会将其静止.如果将布尔标志设置为false和重新编译,则所有信息语句将完全从文件中删除,因为Javac可以说它们将永远不会被调用.
如果您希望能够在运行时启用/禁用信息记录,那么您需要使用一种方法,而不是恒定的布尔标志,而无需每次调用该方法.根据该方法的实现,Hotspot May 能够优化支票,但如上所述,请不要指望它.
问题描述
Suppose I have code like :
log.info("Now the amount" + amount + " seems a bit high")
and I would replace the log method with a dummy implementation like :
class Logger { ... public void info() {} }
Will the optimizer inline it and will the dead code removal remove the parameter construction if no side effects are detected?
推荐答案
I would guess that the compiler (javac) will not, but that the just in time compiler very likely will.
For it to work however, it has to be able to deduct that whatever instructions you use to generate the parameter have no side effects. It should be able to do that for the special case of strings, but it might not for other methods.
To be sure, make a small benchmark that compares this with the code that Jesper suggested and see, whichever is faster or if they are equally fast.
Also see here: http://www.ibm.com/developerworks/java/library/j-jtp12214/index.html#3.0
其他推荐答案
The important answer is: it might do.
I don't think you should be relying on any particular behaviour of the optimiser. If your code runs acceptably fast without optimisation, then you may or may not get a performance boost, but the good news is your solution will be fine regardless. If performance is dreadful when non-optimised, it's not a good solution.
The problem with relying on the optimiser is that you're setting yourself up to conform to an invisible contract that you have no idea of. Hotspot will perform differently in other JDK/JRE versions, so there's no guarantee that just because it runs fine on your exact JVM, it'll run fine elsewhere. But beyond that, the exact optimisations that take place may depend on environmental issues such as the amount of free heap, the amount of cores on the machine, etc.
And even if you manage to confirm it works fine in your situation right now, you've just made your codebase incredibly unstable. I know for a fact that one of the optimisations/inlinings that Hotspot does depends on the number of subclasses loaded and used for a non-final class. If you start using another library/module which loads a second implementation of log - BANG, the optimisation gets unwound and performance is terrible again. And good luck working out how adding a third party library to your classpath toasts your app's internal performance...
Anyway, I don't think you're asking the real question. In the case you've described, the better solution is not to change the info method's implementation, but change the calls to no-ops (i.e. comment them out). If you want to do this across a whole slew of classes at once, at compile time, you can use a type of IFDEF like so:
public class Log { public static final boolean USE_INFO = true; public void info() { ... } ... }
and then in your class:
if (Log.USE_INFO) { log.info("Now the amount" + amount + " seems a bit high"); }
Now the compiler (javac, not Hotspot) can see that the boolean condition is constant and will elide it when compiling. If you set the boolean flag to false and recompile, then all of the info statements will be stripped from the file completely as javac can tell that they will never be called.
If you want to be able to enable/disable info logging at runtime, then instead of a constant boolean flag you'll need to use a method and here's there's nothing for it but to call the method every time. Depending on the implementation of the method, Hotspot may be able to optimise the check but as I mentioned above, don't count on it.