Javaアプリケーションのパフォーマンスは、次の方法で向上させることができます。
この項では、Oracle Database 11gリリース1(11.1)以降で導入されているJust-In-Time(JIT)コンパイラについて説明します。この項の内容は、次のとおりです。
注意: 以前のバージョンのOracle Databaseで使用されていたコンパイラが、JITコンパイラに切り替えられています。 |
Oracle 11gリリース1(11.1)以降には、Oracle JVM環境用のJust-In-Time(JIT)コンパイラがあります。Oracle JVM用のJITコンパイラでは、外部のメカニズムを使用せずにコードの無効化、再コンパイルおよび格納を管理するため、実行速度が上がります。このコンパイラは、動的に収集されたプロファイル・データに基づき、ネイティブのコンピュータ・コードをコンパイルするためにJavaメソッドを透過的に選択し、Javaセッションの実行でこれらを動的に使用できるようにします。さらに、Oracle JVMのクラスの解決モデルを利用して、データベースのコール、セッションまたはインスタンス間でコンパイル済Javaメソッドをオプションで存続できるようにします。Javaコードのセマンティクスが変わらないと判断される場合、このように存続させることで、セッションまたはインスタンス間の不要な再コンパイルのオーバーヘッドが回避されます。
JITコンパイラは、java_jit_enabled
と呼ばれるブール値の新しい初期化パラメータで制御します。java_jit_enabled
パラメータの値をtrue
に指定して使用頻度の高いJavaメソッドを実行する場合、そのJavaメソッドはJITコンパイラによってネイティブ・コードに自動的にコンパイルされ、インスタンスのすべてのセッションで使用できるようになります。また、java_jit_enabled
パラメータをtrue
に設定すると、JITコンパイルが中止し、すでにコンパイルしたメソッドを解析に戻します。VMは、包含Javaクラスの次の再解決のように、必要に応じてJavaメソッドのネイティブ・コードを自動的に再コンパイルします。
JITコンパイラは、インスタンスの1つのバックグラウンド・プロセスでMMONスレーブとして実行されます。そのため、JITコンパイラが実行中で、メソッドをアクティブにコンパイルしている際には、このCPUとメモリー・リソースを消費するバックグラウンド・プロセスが、アクティブなユーザーJavaセッションと平行して表示されます。
次に、以前のバージョンのOracleデータベースで使用されるコンパイル方法よりも優れたJITコンパイルの利点を示します。
JITコンパイルは、透過的に動作します。
JITコンパイルは、Javaクラスのパフォーマンスを高速化します。
Javaコードのセマンティクスが変わらないと判断される場合、JITが格納したコンパイル済コードにより、セッションまたはインスタンス間のJavaプログラムの再コンパイルが回避されます。
JITコンパイルは、Cコンパイラが不要です。
JITコンパイルは、一部の配列境界チェックを行いません。
JITコンパイルは、ブロック内の共通副次式を除去します。
JITコンパイルは、空のメソッドを除去します。
JITコンパイルは、ローカル変数の割当てを登録するための領域を定義します。
JITコンパイルは、フロー分析の必要がありません。
JITコンパイルは、インライン・コードを制限します。
11gリリース1 (11.1)以降では、DBMS_JAVA
パッケージが次の新しいpublicメソッドによって拡張され、同期メソッドのコンパイルを制御し、解析したメソッドの実行に戻すためのJavaエントリ・ポイントが提供されます。
set_native_compiler_option
このプロシージャは、ネイティブ・コンパイラのオプションを現行スキーマの指定の値に設定します。optionNameで指定したオプションで値の重複が許可されない場合、この値は無視されます。
PROCEDURE set_native_compiler_option(optionName VARCHAR2, value VARCHAR2);
unset_native_compiler_option
このプロシージャは、現行スキーマについて、ネイティブ・コンパイラのオプション/値のペアの設定を解除します。optionNameで指定したオプションで値の重複が許可されない場合、この値は無視されます。
PROCEDURE unset_native_compiler_option(optionName VARCHAR2, value VARCHAR2);
compile_class
このファンクションは、現行スキーマのclassnameで特定されるクラスで定義されたすべてのメソッドをコンパイルします。コンパイルが成功したメソッドの数を戻します。クラスが存在しない場合、ORA-29532 (捕捉されないJava例外)
が発生します。
FUNCTION compile_class(classname VARCHAR2) return NUMBER;
uncompile_class
このファンクションは、現行スキーマのclassnameで特定されるクラスで定義されたすべてのメソッドをアンコンパイルします。アンコンパイルが成功したメソッドの数を戻します。引数permanentpの値がゼロ以外の場合、これらのメソッドを動的アンコンパイルが永久に可能であるものとしてマークします。それ以外は、今後の動的な再コンパイルの対象となります。クラスが存在しない場合、ORA-29532 (捕捉されないJava例外)
が発生します。
FUNCTION uncompile_class(classname VARCHAR2, permanentp NUMBER default 0) return NUMBER;
compile_method
このファンクションは、現行スキーマのclassnameで特定されるクラスで定義されたnameおよびJava typeシグネチャで指定したメソッドをコンパイルします。コンパイルが成功したメソッドの数を戻します。クラスが存在しない場合、ORA-29532 (捕捉されないJava例外)が発生します。
FUNCTION compile_method(classname VARCHAR2, methodname VARCHAR2, methodsig VARCHAR2) return NUMBER;
uncompile_method
このファンクションは、現行スキーマのclassnameで特定されるクラスで定義されたnameおよびJava typeシグネチャで指定したメソッドをアンコンパイルします。アンコンパイルが成功したメソッドの数を戻します。引数permanentpの値がゼロ以外の場合、メソッドを動的アンコンパイルが永久に可能であるものとしてマークします。それ以外は、今後の動的な再コンパイルの対象となります。クラスが存在しない場合、ORA-29532 (捕捉されないJava例外)
が発生します。
FUNCTION uncompile_method(classname VARCHAR2, methodname VARCHAR2, methodsig VARCHAR2, permanentp NUMBER default 0) return NUMBER;
標準およびカスタムのデータベース・インストール・プロセスでは、開発時に標準的なJava使用のために構成されているデータベースが提供されます。ただし、Javaの実行時の使用量は、デプロイされたアプリケーションのシステム・リソースの使用率によって決まります。開発時に使用するリソース率は、実行するアクティビティによって大きく異なる場合があります。次の各項では、メモリーの構成方法、システム・グローバル領域(SGA)メモリーの使用量を調べる方法、およびJavaが使用するメモリーの問題を示すエラーについて説明します。
次のデータベース初期化パラメータを変更して、アプリケーションに必要なメモリー使用量がより正確に反映されるようにメモリー使用量をチューニングできます。
共有プール・メモリーはJVM内のクラス・ローダーによって使用されます。クラス・ローダーは、クラスをロードするたびに平均約8KBのメモリーを使用します。共有プール・メモリーは、データベースにクラスをロードして解決するときに使用されます。また、データベース内でソースをコンパイルする場合やデータベースでJavaリソース・オブジェクトを使用する場合にも使用されます。
SHARED_POOL_SIZE
で指定したメモリーは、loadjava
ツールの使用時に一時的に消費されます。データベース初期化プロセスでは、約8,000クラスのJavaバイナリをロードして解決するため、SHARED_POOL_SIZE
を96MBに設定する必要があります。コール仕様を作成するとき、および実行時に動的にロードされたJavaクラスをシステムで追跡するときも、SHARED_POOL_SIZE
リソースが消費されます。
Oracle JVMメモリー・マネージャでは、主にJavaメソッドとクラス定義のメモリー内表現と、共有サーバー・モードでコール終了時にセッション領域に移行した静的Javaの状態のためにJAVA_POOL_SIZE
を使用します。前者の場合は、メモリー・コストをすべてのJavaユーザー間で分担します。後者の場合は、各セッションの静的変数で保持する実際の状態数に基づいて、JAVA_POOL_SIZE
の値が変わります。ただし、最小値を50MBにすることをお薦めします。
このパラメータを使用すると、1つのセッションにおけるJavaのメモリー使用量に弱い制限を指定でき、Javaのメモリー制限を増やす必要がある場合は警告を表示できます。メモリーが割り当てられるたびに、割り当てられたメモリーの合計量がこの制限に対してチェックされます。
ユーザーのセッション中にJavaの状態がこのサイズを超えると、Oracle JVMが警告を生成し、トレース・ファイルに書き込みます。この警告は情報用のメッセージでアプリケーションに影響を与えませんが、デプロイするクラスのメモリー要件、特にセッション領域の使用量に関する要件を把握して管理する必要があります。
注意: このパラメータは共有サーバー環境にのみ適用できます。 |
ユーザーがコール可能でサーバー上で実行されているJavaプログラムを、メモリー使用量を制限しない方法で実行できる場合は、このパラメータを使用して、使用可能なセッション領域に対して強い制限を設定できます。デフォルトは4GBです。この上限は、通常到達することのない高い値に設定します。
ユーザーのセッション中のJavaの状態がこのサイズを超えそうになると、メモリー不足障害が発生します。
注意: このパラメータは共有サーバー環境にのみ適用できます。 |
データベースのインストール・テンプレートのJAVA_POOL_SIZE
およびSHARED_POOL_SIZE
に対して、デフォルト値を設定できます。
図9-1に示すように、これらの値は、Database Configuration Assistantの「メモリー」セクションで変更できます。
Javaプール・メモリーはSGAのサブセットで、ページワイズに調整する必要があるメモリー用にJavaによって排他的に使用されます。大部分はこのように使用されますが、Javaクラスの共有定義にメモリーのすべてが使用されるわけではありません。Javaプール・メモリーの他の使用方法は、Oracle Databaseサーバーの実行モードによって異なります。
専用サーバーで使用されるJavaプール・メモリー
次に、専用サーバーで使用されるJavaプール・メモリーの構成を示します。
使用される各Javaクラスのほとんどの共有部分。
これには、コード・ベクトルやメソッドなどの読取り専用メモリーが含まれます。合計すると、各クラスについて約4KBから8KBになります。
各セッションのセッション当たりのJavaの状態は使用されません。
専用サーバーの場合、これはSGAではなく、プログラム・グローバル領域(PGA)内のユーザー・グローバル領域(UGA)に格納されます。
専用サーバーでは、必要なJavaプール・メモリー合計は実行するアプリケーションによって異なり、通常、10から50MB程度になります。
共有サーバーで使用されるJavaプール・メモリー
次に、共有サーバーで使用されるJavaプール・メモリーの構成を示します。
使用される各Javaクラスのほとんどの共有部分。
これには、ベクトルやメソッドなどの読取り専用メモリーが含まれます。合計すると、通常、各クラスについて約4KBから8KBになります。
セッション・メモリーごとに使用されるUGAの一部は、Javaプール・メモリーから割り当てられます。特に、データベースのコール間で使用中になっているオブジェクトのメモリーは、常にJavaプールから割り当てられます。
Javaプール・メモリーのサイズは制限されているため、アプリケーションで必要なメモリー量を見積り、アプリケーションで作成する同時実行セッション数を乗じて、必要なJavaプール・メモリーの総量を計算する必要があります。各UGAは必要に応じて拡大または縮小できます。ただし、UGA全体が一定のJavaプール領域に収まるようにしてください。
共有サーバーでは、Javaプールは非常に大きくなる場合があります。Java集中型のマルチ・ユーザー・アプリケーションでは、100MB以上が必要になる場合があります。
注意: クライアントでコードをコンパイルしてからサーバーにロードするのではなく、サーバー上でコードをコンパイルする場合は、JAVA_POOL_SIZE をデフォルトの20MBより大きいサイズに設定する必要がある場合があります。 |
V$SGASTAT
表を表示すると、Javaプール・メモリーの使用量を調べることができます。この表の行には、プール、名前およびバイト数が表示されます。特に、最後の2行にはJavaプール・メモリーの使用量と空き容量が表示されます。この2行の数字の合計値は、データベース初期化ファイルに設定したバイト数と等しくなります。
SVRMGR> select * from v$sgastat; POOL NAME BYTES ----------- -------------------------- ---------- fixed_sga 69424 db_block_buffers 2048000 log_buffer 524288 shared pool free memory 22887532 shared pool miscellaneous 559420 shared pool character set object 64080 shared pool State objects 98504 shared pool message pool freequeue 231152 shared pool PL/SQL DIANA 2275264 shared pool db_files 72496 shared pool session heap 59492 shared pool joxlod: init P 7108 shared pool PLS non-lib hp 2096 shared pool joxlod: in ehe 4367524 shared pool VIRTUAL CIRCUITS 162576 shared pool joxlod: in phe 2726452 shared pool long op statistics array 44000 shared pool table definiti 160 shared pool KGK heap 4372 shared pool table columns 148336 shared pool db_block_hash_buckets 48792 shared pool dictionary cache 1948756 shared pool fixed allocation callback 320 shared pool SYSTEM PARAMETERS 63392 shared pool joxlod: init s 7020 shared pool KQLS heap 1570992 shared pool library cache 6201988 shared pool trigger inform 32876 shared pool sql area 7015432 shared pool sessions 211200 shared pool KGFF heap 1320 shared pool joxs heap init 4248 shared pool PL/SQL MPCODE 405388 shared pool event statistics per sess 339200 shared pool db_block_buffers 136000 java pool free memory 30261248 java pool memory in use 19742720 37 rows selected.
クラスのロード中にメモリー不足になると、エラーが何も表示されずにロードが失敗し、データベースに無効なクラスが残されます。無効なクラスをコールまたは解決しようとすると、実行時にClassNotFoundException
インスタンスまたはNoClassDefFoundException
インスタンスがスローされます。破損したクラス・ファイルをロードしようとした場合も同じ例外が発生します。この場合には次の処置を実行してください。
サーバーにロードするセットに、実際にクラスが含まれていることを検証します。
loadjava -force
オプションを使用して、新しいクラスをロードすることによって、サーバーにすでに常駐しているクラスを強制的に置き換えます。
loadjava -resolve
オプションを使用して、ロード・プロセス時にクラスの解決を試みます。これによって、実行時ではなくロード時に、欠落しているクラスを捕捉できます。
新しくロードされたクラスの状態を再確認するために、そのクラスが含まれているスキーマのデータベースに接続して、次のように実行します。
SELECT * FROM user_objects WHERE object_name = dbms_java.shortname('');
STATUS
フィールドにVALID
と表示されていることを確認してください。loadjava
ツールからメモリーの問題や接続を失うなどの障害が発生した場合は、SHARED_POOL_SIZE
およびJAVA_POOL_SIZE
を増やして再試行してください。
データベース・パフォーマンス・ビューv$sesstat
は、多数のJavaメモリー使用量統計情報を記録します。この統計情報は、Javaコール中に頻繁に更新されます。次の例は、SIDが102のデータベース・セッションのJavaコールの戻り値とセッション・ヒープ統計情報を示します。
SQL> select s.sid, n.name p_name, st.value from v$session s, v$sesstat st, v$statname n where s.sid=102 and s.sid=st.sid and n.statistic# = st.statistic# and n.name like 'java%'; SID P_NAME VALUE ---------- ---------------------------------------- ---------- 102 java call heap total size 6815744 102 java call heap total size max 6815744 102 java call heap used size 668904 102 java call heap used size max 846920 102 java call heap live size 667112 102 java call heap live size max 704312 102 java call heap object count 13959 102 java call heap object count max 17173 102 java call heap live object count 13907 102 java call heap live object count max 14916 102 java call heap gc count 432433 102 java call heap collected count 123196423 102 java call heap collected bytes 5425972216 102 java session heap used size 444416 102 java session heap used size max 444416 102 java session heap live size 444416 102 java session heap live size max 444416 102 java session heap object count 0 102 java session heap object count max 0 102 java session heap live object count 0 102 java session heap live object count max 0 102 java session heap gc count 0 102 java session heap collected count 0 102 java session heap collected bytes 0 24 rows selected.