我有一些Java代码在BitSet上执行按位操作。我有一个操作列表,可以通过循环来“解释”它们,但对我来说很重要的是我可以尽快执行这些操作,所以我一直在尝试动态生成代码来应用它们。我生成Java源代码来执行操作,并使用Javassist编译实现这些操作的类。
不幸的是,我动态生成的代码比解释代码运行得慢。看来这是因为HotSpot正在优化解释的代码,但没有优化编译的代码:运行几千次之后,我解释的代码运行速度是最初的两倍,但我的编译代码没有显示加速。与此假设一致,我的解释代码最初比编译代码慢,但最终更快。
我不确定为什么会这样。我的猜测是,Javassist可能使用类HotSpot不接触的类加载器。但我不是Java中的类加载专家,所以我不确定这是一个合理的猜测还是如何进行测试。以下是我使用Javassist创建和加载类的方法:
ClassPool pool = ClassPool.getDefault();
CtClass tClass = pool.makeClass("foo");
// foo implements MyInterface, with one method
tClass.addInterface(pool.get(MyInterface.class.getName()));
// Get the source for the method and add it
CtMethod tMethod = CtNewMethod.make(getSource(), tClass);
tClass.addMethod(tMethod);
// finally, compile and load the class
return (MyInterface)tClass.toClass().newInstance();
有没有人知道这里发生了什么?我真的很感激你能给予的任何帮助。
我在Windows XP 32位上使用Sun 1.6服务器JVM。
答案 0 :(得分:3)
HotSpot并不关心代码的来源。例如,它很高兴内联通过虚方法调用调用的代码,其中的实现由不同的类加载器加载。
我建议您在源代码中写出您尝试为此基准测试执行的操作,然后对其进行基准测试。编写生成代码的示例通常更容易,而不是编写生成器。
有很多原因导致HotSpot可能无法尽可能地优化代码。例如,非常长的方法往往不会内联或将方法内联到它们中。
答案 1 :(得分:1)
我想我明白这里发生了什么。我的第一个错误是生成太长的方法。在我修复之后,我注意到虽然我生成的代码仍然较慢,但它最终接近了解释代码的速度。
我认为最大的加速来自HotSpot优化我的代码。在解释版本中,优化的代码非常少,因此HotSpot会快速处理它。在生成的版本中,有很多代码需要优化,因此HotSpot需要更长的时间来完成所有代码的魔力。
如果我运行基准测试的时间足够长,我现在看到生成的代码表现略好于解释代码。
答案 2 :(得分:1)
有一个JVM设置可以控制编译代码的速度-XX:CompileThreshold = 10000
编译前的方法调用/分支数[-client:1,500]
我不知道这是否会有所帮助,因为在你的例子中,大小似乎起着至关重要的作用。