2

我有一些对 BitSet 执行按位运算的 Java 代码。我有一个操作列表,可以通过循环来“解释”它们,但对我来说重要的是我可以尽快执行这些操作,所以我一直在尝试动态生成代码来应用它们。我生成 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。

4

3 回答 3

3

HotSpot 不关心代码来自哪里。例如,它会愉快地将通过虚拟方法调用调用的代码与由不同类加载器加载的实现进行内联。

我建议您在源代码中写出您尝试为此基准执行的操作,然后对其进行基准测试。编写生成代码的示例通常比编写生成器更容易。

HotSpot 可能无法尽其所能优化代码的原因有很多。例如,很长的方法往往不会被内联或内联方法。

于 2009-05-17T23:12:41.097 回答
1

我想我明白这里发生了什么。我的第一个错误是生成的方法太长了。在我修复它之后,我注意到虽然我生成的代码仍然较慢,但它最终接近了解释代码的速度。

我认为这里最大的加速来自 HotSpot 优化我的代码。在解释版本中,需要优化的代码非常少,因此 HotSpot 很快就会处理它。在生成的版本中,有很多代码需要优化,因此 HotSpot 需要更长的时间才能对所有代码发挥作用。

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

于 2009-05-18T07:28:04.443 回答
1

有一个 JVM 设置可以控制编译代码的速度 -XX:CompileThreshold=10000

编译前的方法调用/分支数 [-client: 1,500]

我不知道这是否会有所帮助,因为在您的示例中,大小似乎起着至关重要的作用。

于 2009-05-18T08:19:54.510 回答