2

BitSetでビット単位の演算を実行するJavaコードがいくつかあります。操作のリストがあり、ループすることで「解釈」できますが、これらの操作をできるだけ早く実行できることが重要なので、動的にコードを生成して適用しようとしています。操作を実行するJavaソースを生成し、Javassistを使用してそれらの操作を実装するクラスをコンパイルします。

残念ながら、動的に生成されたコードは、解釈されたコードよりも実行が遅くなります。これは、HotSpotが解釈されたコードを最適化しているが、コンパイルされたコードを最適化していないためと思われます。数千回実行した後、解釈されたコードは最初の2倍の速度で実行されますが、コンパイルされたコードは高速化されません。この仮説と一致して、私の解釈されたコードは最初はコンパイルされたコードよりも遅いですが、最終的には速くなります。

なぜこれが起こっているのかわかりません。私の推測では、おそらく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();

誰かがここで何が起こっているのかについて考えを持っていますか?私はあなたが与えることができるどんな助けにも本当に感謝します。

WindowsXP32ビットでSun1.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 に答える