最近、私はこれを読んでいました 記事 。
その記事によると、Javaコンパイラ、つまりjavacはバイトコードの生成中に最適化を実行しません。本当ですか?そうであれば、中間コードジェネレータとして実装して冗長性を削除し、生成することができます。最適なコード?
javac
は、もしあれば、ごくわずかな最適化しか行いません。
重要な点は、JITコンパイラーが最適化の大部分を行うことです。大量の情報がある場合に最適に機能します。javac
も最適化を実行すると、その一部が失われる可能性があります。 javac
がなんらかのループのアンロールを実行した場合、JITがそれ自体を一般的な方法で実行するのは困難になります。また、最適化が行われることに関する詳細情報実際にが機能するため、ターゲットプラットフォームを認識しています。
このセクションに着いたとき、私は読書をやめました:
さらに重要なこととして、javacコンパイラーは、ループの展開、代数の単純化、強度の削減などの単純な最適化を実行しません。これらの利点とその他の単純な最適化を取得するには、プログラマはJavaソースコードでそれらを実行し、javacコンパイラに依存せずにそれらを実行する必要があります。
まず、Javaソースコードでループアンロールを実行することは、決して良い考えではありません。javac
が最適化の方法であまり機能しない理由は、JITによって行われるためです。 JVM内のコンパイラー。これにより、コンパイラーが実行できるよりも優れた決定を行うことができます。これは、最も実行されているコードを正確に確認できるためです。
javac
コンパイラは、コマンドラインで-o
を渡して最適化されたバイトコードを生成するオプションをかつてサポートしていました。
ただし、J2SE1.3以降、 HotSpot JVMはプラットフォームに同梱 。これにより、ジャストインタイムコンパイルや一般的な実行パスの適応最適化などの動的な手法が導入されました。したがって、-o
は、このバージョンを開始したJavaコンパイラによって無視されました。
Ant javac
タスクとそのoptimize
属性について読んでいるときにこのフラグに遭遇しました:
ソースを最適化してコンパイルする必要があるかどうかを示します。デフォルトは
off
です。 注このフラグは、JDK 1.3以降のSunのjavac
によって無視されることに注意してください(コンパイル時の最適化が不要なため)。
コンパイル時の最適化に対するHotSpot JVMの動的最適化の利点は このページ で説明されています。
サーバーVMには、C++コンパイラーの最適化によって実行される同じタイプの最適化の多くをサポートする高度な適応型コンパイラーや、従来のコンパイラーでは実行できないいくつかの最適化が含まれています。仮想メソッドの呼び出し。これは、静的コンパイラよりも競争力があり、パフォーマンスが優れています。適応型最適化テクノロジーは、そのアプローチが非常に柔軟であり、通常、高度な静的分析およびコンパイル技術よりも優れています。
私は過去に出力されたJavaバイトコード(FrontEndと呼ばれるアプリを使用)を研究しました。定数をインライン化する(静的ファイナル)と固定式を事前計算する(2のような)以外は、基本的に最適化を行いません。 * 5および "ab" + "cd")これは、分解が非常に簡単な理由の一部です(JADと呼ばれるアプリを使用)。
また、Javaコードを最適化するための興味深い点をいくつか発見しました。これにより、内部ループの速度が2.5倍向上しました。
メソッドには5つのクイックアクセス変数があります。これらの変数が呼び出されると、他のすべての変数よりも高速になります(おそらくスタックの保守のため)。メソッドのパラメーターもこれら5にカウントされます。したがって、100万回実行されるforループ内のコードがある場合、それらの変数をメソッドの最初に割り当て、パラメーターはありません。
ローカル変数はフィールドよりも高速であるため、内部ループ内でフィールドを使用する場合は、メソッドの開始時にローカル変数に割り当てることにより、これらの変数をキャッシュします。内容ではなく参照をキャッシュします。 (例:int [] px = this.pixels;)
バイトコードを最適化するには、 Proguard を使用できます。
他の人が指摘したように、メインストリームJVMのJITは、コードをコンパイルするときにコードを最適化し、より多くのコンテキストにアクセスできるため、おそらくProguardよりもパフォーマンスが優れています。これは、より単純なVMでは当てはまらない場合があります。 Androidの世界では、Dalvik(VM以前に付属していたAndroidロリポップ)。
また、Proguardは、バイトコードを圧縮して難読化します。これは、クライアント側アプリケーションを出荷するときに必要です(最適化を使用しない場合でも)。
JITオプティマイザーによって実行時に最適化されるため、コンパイラーはバイトコードを最適化しません。
ターゲットとするランタイムのタイプにJITオプティマイザーがない場合(JITコンパイラーがある場合でも)、またはAOTコンパイルを使用している場合は、ProguardやAllatoriなどの最適化難読化ツールを使用することをお勧めします。