2009-05-17 50 views
2

我有一些Java代码在BitSet上执行按位操作。我有一个操作列表,可以通过遍历它们来“解释”它们,但对我来说我可以尽快执行这些操作很重要,所以我一直试图动态生成代码来应用它们。我生成Java源代码来执行操作并编译一个使用Javassist实现这些操作的类。为什么生成的Java代码执行操作比“解释器循环”运行速度慢?

不幸的是,我的动态生成的代码运行速度比解释代码慢。看起来,这是因为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

只是为了确认您正在讨论与多个方法调用相关的时间安排,但不*包括班级建设? – 2009-05-18 08:27:00

+0

@mP - 是的,我只计算运行这个类所需的时间,不包括编译时间和内容。 – 2009-05-18 16:54:44

回答

3

HotSpot不关心代码来自哪里。例如,它会很高兴地通过虚拟方法调用来调用内嵌的代码,而调用的方法是由不同的类加载器加载的实现。

我建议你在源代码中写出你正在为这个基准测试执行的操作,然后进行基准测试。写一个生成代码的例子比写发生器要容易得多。

有很多原因可能导致HotSpot不尽可能优化代码。例如,非常长的方法往往不会内联或内联方法。

1

我想我明白这里发生了什么。我的第一个错误是产生过长的方法。在我解决这个问题后,我注意到虽然我生成的代码仍然比较慢,但最终还是接近了解释代码的速度。

我认为这里最大的加速来自HotSpot优化我的代码。在解释版本中,只有很少的代码需要优化,所以HotSpot快速处理它。在生成的版本中,有很多代码需要优化,所以HotSpot需要更长时间才能在所有代码上发挥它的魔力。

如果我足够长时间运行我的基准测试,现在我可以看到我的生成代码比解释代码稍微好一些。

1

有一个JVM设置控制代码是如何快速应当编译-XX:CompileThreshold = 10000

方法调用的数目/编译前分支[-client:1500]

我不知道这是否会有所帮助,因为在你的例子中,规模似乎扮演着重要的角色。

相关问题