Java Platform Standard Edition

Java仮想マシン・ガイド

リリース9

E90919-02(原本部品番号:E68512-05)

2017年10月

このドキュメントでは、Java HotSpot VMテクノロジを含むJava仮想マシン・テクノロジの機能について説明します。

Java Platform, Standard Edition Java仮想マシン・ガイド, リリース9

E90919-02

Copyright © 1993, 2017, Oracle and/or its affiliates.  All rights reserved.

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs. No other rights are granted to the U.S. Government.

このソフトウェアもしくはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアもしくはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

OracleおよびJavaはOracle Corporationおよびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。適用されるお客様とOracle Corporationとの間の契約に別段の定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。適用されるお客様とOracle Corporationとの間の契約に定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

目次

タイトルおよび著作権情報

はじめに

- 対象読者

- ドキュメントのアクセシビリティについて

- 関連ドキュメント

- 表記規則

1 Java仮想マシン・テクノロジの概要

2 コンパイラ・コントロール

- ディレクティブの記述

- コンパイラ・コントロール・オプションのリスト

- ディレクティブ・ファイルの記述

- コンパイラ・ディレクティブの記述

- コンパイラ・ディレクティブのメソッド・パターンの記述

- インライン・ディレクティブ・オプションの記述

- Enableオプションによる重複の回避

- ディレクティブの理解

- デフォルト・ディレクティブとは

- コードへのディレクティブの適用

- コンパイラ・コントロールと下位互換性

- ディレクティブ・ファイルを操作するためのコマンド

- コンパイラ・ディレクティブとコマンドライン

- コンパイラ・ディレクティブと診断コマンド

- Javaプロセス識別番号の取得

- 診断コマンドによるディレクティブの追加

- 診断コマンドによるディレクティブの削除

- 診断コマンドによるディレクティブの出力

- ディレクティブ・スタック内のディレクティブの順序

3 ガベージ・コレクション

4 クラス・データ共有

- クラス・データ共有の概要

- 共有アーカイブの再生成

- 手動によるクラス・データ共有の制御

5 Java HotSpot仮想マシン・パフォーマンス向上

- コンパクト文字列

- 階層型コンパイル

- 圧縮Ordinary Object Pointer

- ゼロ・ベース圧縮Ordinary Object Pointer

- エスケープ解析

6 非Java言語のサポート

- 非Java言語機能の概要

- 静的型付けと動的型付け

- 静的型付け言語は強く型付けされた言語であるとはかぎらない

- 動的型付け言語のコンパイルの課題

- invokedynamic命令

- ブートストラップ・メソッドを定義する

- 定数プール・エントリを指定する

- 定数プールの例

- invokedynamic命令を使用する

7 シグナル・チェーン

8 ネイティブ・メモリー・トラッキング

- 主な機能

- ネイティブ・メモリー・トラッキングの使用

- NMTの有効化

- jcmdを使用したNMTデータへのアクセス

- VM終了時のNMTデータの取得

9 HotSpot VM内のDTraceプローブ

- hotspotプロバイダの使用

- VMライフサイクル・プローブ

- スレッド・ライフサイクル・プローブ

- クラス・ロード・プローブ

- ガベージ・コレクション・プローブ

- メソッド・コンパイル・プローブ

- モニター・プローブ

- アプリケーション追跡プローブ

- hotspot_jniプロバイダの使用

- サンプルDTraceプローブ

10 致命的エラー・レポート

- エラー・レポートの例

11 Java仮想マシン関連のリソース

- ツール

はじめに

このドキュメントは、Java仮想マシン・テクノロジでサポートされている機能に関する情報を提供します。

対象読者

このドキュメントは、Java HotSpotテクノロジを使用してアプリケーションを構築する経験豊富な開発者を対象としています。

ドキュメントのアクセシビリティについて

Oracleのアクセシビリティについての詳細情報は、Oracle Accessibility ProgramのWeb サイト(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc)を参照してください。

Oracle Supportへのアクセス

サポートをご購入のOracleのお客様は、My Oracle Supportにアクセスして電子サポートを受けることができます。詳細情報は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info) か、聴覚に障害のあるお客様は (http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs)を参照してください。

関連ドキュメント

Oracle Java Development Kit (JDK) 9のその他のガイドについては、Oracle JDK 9のドキュメントを参照してください。

表記規則

このマニュアルでは次の表記規則を使用します。

規則

意味

太字

太字は、操作に関連するGraphical User Interface要素、または本文中で定義されている用語および用語集に記載されている用語を示します。

イタリック体

イタリックは、ユーザーが特定の値を指定するプレースホルダ変数を示します。

固定幅フォント

固定幅フォントは、段落内のコマンド、URL、サンプル内のコード、画面に表示されるテキスト、または入力するテキストを示します。

1 Java仮想マシン・テクノロジの概要

この章では、Java仮想マシン(JVM)の実装およびJava HotSpotテクノロジの主な機能について説明します。

- 適応型コンパイラ: アプリケーションの起動に標準のインタプリタが使用されます。アプリケーションを実行すると、コードが解析され、パフォーマンス・ボトルネックまたはホット・スポットが検出されます。Java HotSpot VMは、パフォーマンスを向上させるためにパフォーマンスに不可欠なコード部分はコンパイルしますが、ほとんど使用されないコード(アプリケーションの大部分)はコンパイルしません。Java HotSpot VMは、適応型コンパイラを使用して、インライン化などの技術で、コンパイルしたコードを最適化する方法を判断します。

- 高速メモリー割当てとガベージ・コレクション: Java HotSpotテクノロジは、オブジェクトの高速メモリー割当てに加え、高速で効率のよい、最先端のガベージ・コレクタを提供します。

- スレッドの同期: Java HotSpotテクノロジは、大規模なメモリー共有マルチプロセッサ・サーバーで使用するために拡張できるように設計された、スレッド処理機能を提供します。

Oracle Java Runtime Environment (JRE) 8以前では、クライアント、サーバーおよび埋込みシステムとして一般に使用される構成用に、様々なJVM (クライアントVM、サーバーVMおよび最小VM)の実装がサポートされていました。ほとんどのシステムでサーバーVMを活用できるようになったため、Oracle Java Runtime Environment (JRE) 9ではそのVM実装のみを提供します。

2 コンパイラ・コントロール

コンパイラ・コントロールは、コンパイラ・ディレクティブ・オプションを介してJava仮想マシン(JVM)のコンパイルを制御する方法を提供します。制御のレベルは、実行時に管理可能であり、メソッドによって異なります。

コンパイラ・ディレクティブは、コンパイルを行う方法についてJVMに伝える指示です。ディレクティブは、コンパイル処理の制御において、メソッドに応じた精度を提供します。ディレクティブは、小規模で制御可能なJVMコンパイラ・テストを記述するための強力なツールです。これらのテストはJVM全体を再起動することなく実行できます。コンパイラ・コントロールは、JVMコンパイラのバグの回避策を作成するためにも役立ちます。

コマンドラインからプログラムを起動する際、コンパイラ・ディレクティブが含まれるファイルを指定できます。また、診断プログラムを使用して、すでに実行中のプログラムに対してディレクティブの追加と削除を行うこともできます。

コンパイラ・コントロールはCompileCommandを置き換えるもので、下位互換性を有しています。

トピック:

- ディレクティブの記述

- ディレクティブ・ファイルの記述

- コンパイラ・ディレクティブの記述

- コンパイラ・ディレクティブのメソッド・パターンの記述

- インライン・ディレクティブ・オプションの記述

- Enableオプションによる重複の回避

- ディレクティブの理解

- デフォルト・ディレクティブとは

- コードへのディレクティブの適用

- コンパイラ・コントロールと下位互換性

- ディレクティブ・ファイルを操作するためのコマンド

- コンパイラ・ディレクティブとコマンドライン

- コンパイラ・ディレクティブと診断コマンド

- ディレクティブ・スタック内のディレクティブの順序

ディレクティブの記述

このトピックでは、コンパイラ・コントロールのオプションと、それらのオプションからディレクティブを記述する手順について確認します。

トピック:

- コンパイラ・コントロール・オプションのリスト

- ディレクティブ・ファイルの記述

- コンパイラ・ディレクティブの記述

- コンパイラ・ディレクティブのメソッド・パターンの記述

- インライン・ディレクティブ・オプションの記述

- Enableオプションによる重複の回避

コンパイラ・コントロール・オプションのリスト

オプションはコンパイルに対する命令です。オプションは、メソッドに応じた精度を提供します。使用可能なオプションはコンパイラによって異なり、特定の値の型を必要とします。

表2-1 共通オプション

オプション

説明

値の型

デフォルト値

Enable

falseに設定された場合、ディレクティブを非表示にし、比較不可とします。これはオプションの重複を回避するために役立ちます。Enableオプションによる重複の回避を参照してください。

bool

true

Exclude

コンパイルからメソッドを除外します。

bool

false

BreakAtExecute

JVMをデバッグする際、指定したメソッドの開始時に実行を停止するブレークポイントを設定します。

bool

false

BreakAtCompile

JVMをデバッグする際、指定したメソッドの開始時にコンパイルを停止するブレークポイントを設定します。

bool

false

Log

指定したメソッドのみをログに記録します。最初にコマンドライン・オプション-XX:+LogCompilationを設定する必要があります。デフォルト値falseは、コンパイルされたすべてのメソッドをログに記録します。

bool

false

PrintAssembly

外部disassembler.soライブラリを使用して、バイト・コード化されたメソッドおよびネイティブ・メソッド用のアセンブリ・コードを出力します。

bool

false

PrintInlining

インライン化されるメソッドおよびその場所を出力します。

bool

false

PrintNMethods

生成されたnmethodを出力します。

bool

false

BackgroundCompilation

バックグラウンド・タスクとしてメソッドをコンパイルします。バックグラウンド・コンパイルが終了するまで、メソッドはインタプリタ・モードで実行されます。値falseは、フォアグラウンド・タスクとしてメソッドをコンパイルします。

bool

true

ReplayInline

対応するグローバル・オプションと同じCIReplay機能をメソッドごとに有効にします。

bool

false

DumpReplay

対応するグローバル・オプションと同じCIReplay機能をメソッドごとに有効にします。

bool

false

DumpInline

対応するグローバル・オプションと同じCIReplay機能をメソッドごとに有効にします。

bool

false

CompilerDirectivesIgnoreCompileCommands

すべてのCompileCommandを無視します。

bool

false

DisableIntrinsic

メソッド照合基準に基づいて組込みの使用を無効にします。

ccstr

デフォルト値なし

inline

メソッド照合基準に基づいてメソッドのインライン化を強制または防止します。インライン・ディレクティブ・オプションの記述を参照してください。

ccstr[]

デフォルト値なし

表2-2 C2専用オプション

オプション

説明

値の型

デフォルト値

BlockLayoutByFrequency

低頻度の実行ブランチをホット・パスから移動します。

bool

true

PrintOptoAssembly

外部disassembler.soライブラリを使用して、コンパイル後に生成されたアセンブリ・コードを出力します。これにはJVMのデバッグ・ビルドが必要です。

bool

false

PrintIntrinsics

使用される組込みメソッドおよびその場所を出力します。

bool

false

TraceOptoPipelining

パイプライン情報をメソッドごとに追跡します(対応するグローバル・オプションと同様)。低速および高速のデバッグ・ビルドを目的としています。

bool

false

TraceOptoOutput

パイプライン情報をメソッドごとに追跡します(対応するグローバル・オプションと同様)。低速および高速のデバッグ・ビルドを目的としています。

bool

false

TraceSpilling

変数のスピルを追跡します。

bool

false

Vectorize

ベクトル・レジスタ間で並行して計算を実行します。

bool

false

VectorizeDebug

ベクトル・レジスタ間で並行して計算を実行します。これにはJVMのデバッグ・ビルドが必要です。

intx

0

CloneMapDebug

ベクトル化から生成されたCloneMapを検査できるようにします。これにはJVMのデバッグ・ビルドが必要です。

bool

false

IGVPrintLevel

HotspotのIdeal Graphic Visualizer (IGV)に出力されるコンパイラ・グラフのポイントを指定します。値が高いことは粒度が高いことを意味します。

intx

0

MaxNodeLimit

単一のメソッドのコンパイル時に使用されるノードの最大数を設定します。

intx

80000

値の型ccstrはメソッド・パターンです。コンパイラ・ディレクティブのメソッド・パターンの記述を参照してください。

デフォルト・ディレクティブは、コンパイラ・オプションのデフォルト値を提供します。デフォルト・ディレクティブとはを参照してください。

ディレクティブ・ファイルの記述

個々のコンパイラ・ディレクティブは、ディレクティブ・ファイルに記述します。アクティブなディレクティブのスタックに追加できるのはディレクティブ・ファイルのみで、個々のディレクティブは追加できません。

1. .json拡張子を使用してファイルを作成します。ディレクティブ・ファイルは、JSON構文のサブセットを使用して記述し、若干の追加と変更を行います。

2. 作業のベースとなるテンプレートとして次の構文を挿入します。

[  //Array of Directives
{   //Directive Block
//Directive 1
},
{   //Directive Block
//Directive 2
},
]

このテンプレートの構成要素は次のとおりです。

ディレクティブの配列:

- ディレクティブ・ファイルはディレクティブ・ブロックの配列を格納します。この配列は1対のカッコ([])で示されます。

- ファイルに含まれるディレクティブ・ブロックが1つのみの場合、カッコはオプションです。

ディレクティブ・ブロック:

- 1つのブロックは1対のカッコ({})で示されます。

- 1つのブロックには1つのディレクティブが含まれます。

- ファイルには任意の数のディレクティブ・ブロックを含めることができます。

- ブロックはカンマ(,)で区切ります。

- 配列内の最後のブロックに続くカンマはオプションです。

個々のディレクティブ:

- 個々のディレクティブはディレクティブ・ブロック内に存在する必要があります。

- ファイルに複数のディレクティブ・ブロックが含まれている場合、そのファイルには複数のディレクティブを含めることができます。

コメント:

- 単一行のコメントは、2つのスラッシュ(//)を使用して挿入します。

- 複数行のコメントは使用できません。

3. テンプレートでディレクティブ・ブロックを追加または削除して、ファイルに含めるディレクティブの数と一致させます。

4. ディレクティブ・ブロックごとに1つのコンパイラ・ディレクティブを記述します。コンパイラ・ディレクティブの記述を参照してください。

5. 必要に応じてディレクティブ・ブロックを整理しなおします。ファイル内のディレクティブの順序は重要です。記述されたディレクティブが配列の先頭に近いほど、優先度が高くなります。詳細は、ディレクティブ・スタック内のディレクティブの順序およびコードへのディレクティブの適用を参照してください。

2つのコンパイラ・ディレクティブを含む作成済のディレクティブ・ファイルの例を次に示します。

[  //Array of directives
{   //Directive Block
//Directive 1
match: ["java*.*", "oracle*.*"],
c1: {
Enable: true,
Exclude: true,
BreakAtExecute: true,
},
c2: {
Enable: false,
MaxNodeLimit: 1000,
},
BreakAtCompile: true,
DumpReplay: true,
},
{   //Directive Block
//Directive 2
match: ["*Concurrent.*"],
c2: {
Exclude:true,
},
},
]

コンパイラ・ディレクティブの記述

コンパイラ・ディレクティブは、ディレクティブ・ファイル内に記述する必要があります。ディレクティブ・ファイルに記述する個々のコンパイラ・ディレクティブごとに、次の手順を繰り返します。

個々のコンパイラ・ディレクティブは、ディレクティブ・ファイルのディレクティブ・ブロック内に記述します。ディレクティブ・ファイルの記述を参照してください。

1. 作業のベースとなるテンプレートとして次のコード・ブロックを挿入して、個々のコンパイラ・ディレクティブを記述します。このコード・ブロックはディレクティブ・ブロックです。

{
match: [],
c1: {
//c1 directive options
},
c2: {
//c2 directive options
},
//Directive options applicable to all compilers
},

2. メソッド・パターンの配列にmatch属性を指定します。コンパイラ・ディレクティブのメソッド・パターンの記述を参照してください。
次に例を示します。

match: ["java*.*", "oracle*.*"],

3. カンマで区切られたディレクティブ・オプションのブロックにc1属性を指定します。これらのオプションはc1コンパイラに対して有効になります。
次に例を示します。

c1: {
Enable: true,
Exclude: true,
BreakAtExecute: true,
},

4. カンマで区切られたディレクティブ・オプションのブロックにc2属性を指定します。このブロックでは、共通のコンパイラ・オプションとc2専用のコンパイラ・オプションを併用できます。
次に例を示します。

c2: {
Enable: false,
MaxNodeLimit: 1000,
},

5. ディレクティブの末尾に、すべてのコンパイラに適用するオプションを指定します。これらのオプションは、共通ブロックの範囲内に記述されているものとみなされます。オプションはカンマで区切ります。
次に例を示します。

BreakAtCompile: true,
DumpReplay: true,

6. ファイルをクリーン・アップします。

a. ディレクティブ・オプションの順序と重複の可能性を確認します。競合がある場合、最後に出現するオプションが優先されます。競合が最も発生しやすいのは、共通ブロックとc1ブロックまたはc2ブロックとの間です(c1ブロックとc2ブロックとの間ではありません)。

b. c2専用ディレクティブ・オプションを共通ブロックに記述しないようにします。共通ブロックは共通オプションとc2専用オプションの組合せを受け入れることができますが、コマンド・ブロック内のc2専用オプションはc1コンパイラに影響を及ぼさないため、この方法でディレクティブを構成すると誤解を招きかねません。かわりに、c2専用オプションをc2ブロック内に記述してください。

c. c1またはc2属性に対応するディレクティブ・オプションがない場合は、そのコンパイラに対する属性と値の構文を省略します。

前述の例に基づく最終的なディレクティブは次のようになります。

{
match: ["java*.*", "oracle*.*"],
c1: {
Enable: true,
Exclude: true,
BreakAtExecute: true,
},
c2: {
Enable: false,
MaxNodeLimit: 1000,
},
BreakAtCompile: true,
DumpReplay: true,
},

JSON形式のディレクティブ・ファイルでは、構文において特定の変更が許容されます。

- 配列およびオブジェクトでは、後に続く余分なカンマはオプションです。

- 属性は文字列であり、必要に応じて引用符で囲まれます。

- 配列に含まれる要素が1つのみの場合、カッコはオプションです。

これを踏まえ、コンパイラ・ディレクティブの有効な例を次に示します。

{
"match": "*Concurrent.*",
c2: {
"Exclude": true,
}
},

コンパイラ・ディレクティブのメソッド・パターンの記述

ccstrはメソッド・パターンです。これは正確に記述しても、ワイルドカード文字で一般化してもかまいません。一致度の高いどのJavaコードに、付随するディレクティブ・オプションを適用するか、またはどのJavaコードをインライン化するかを指定します。

メソッド・パターンを記述するには、次のようにします。

1. package/class.method(parameter_list)の構文を使用して、メソッド・パターンを書式設定します。細かく指定できない場合は、手順2を参照して、ワイルドカード文字でメソッド・パターンを一般化する方法を確認してください。
この書式設定のスタイルを使用するメソッド・パターンの例を次に示します。

java/lang/String.indexOf()

その他の書式設定スタイルも使用できます。これにより、CompileCommandなどの以前のメソッド照合手段との下位互換性が確保されます。前述の例に代わる有効な書式設定には次のものが含まれます。

- java/lang/String.indexOf()

- java/lang/String,indexOf()

- java/lang/String indexOf()

- java.lang.String::indexOf()

Hotspotの出力に合っているため、最後の書式設定スタイルが役立つ場合もあります。

2. メソッド・パターンの一部を一般化する必要がある場合、ワイルドカード文字(*)を挿入します。
手順1のメソッド・パターンの例を適切に一般化したものを次に示します。

- java/lang/String.indexOf*

- *lang/String.indexOf*

- *va/lang*.*dex*

- java/lang/String.*

- *.*

これらの例では、一般化の度合いが増すほど、精度が低くなります。つまり、メソッド・パターンに一致する可能性があるJavaコードが増えるため、危険を伴います。そのため、ワイルドカード文字(*)は慎重に使用することが重要です。

3. メソッド・パターンのシグニチャ部分を変更します。シグニチャはJava仕様に応じて記述されます。シグニチャの照合は厳密である必要があります。そうでないと、シグニチャがワイルドカード文字(*)にデフォルト設定されます。省略されたシグニチャもワイルドカード文字にデフォルト設定されます。シグニチャ自体にワイルドカード文字を含めることはできません。

4. オプション: inlineディレクティブ・オプションを伴うメソッド・パターンを記述する場合、追加の文字をメソッド・パターンの前に付ける必要があります。インライン・ディレクティブ・オプションの記述を参照してください。

インライン・ディレクティブ・オプションの記述

inlineディレクティブ・オプションの属性は、接頭辞つきの特殊コマンドを使用したメソッド・パターンの配列を必要とします。これにより、インライン化するメソッド・パターンとインライン化しないメソッド・パターンを指定します。

1. ディレクティブの共通ブロック、c1ブロックまたはc2ブロックに、inline: と記述します。

2. これに、慎重に順序づけたメソッド・パターンの配列を付け加えます。最初に一致したメソッド・パターンの接頭辞つきコマンドが実行されます。配列内の残りのメソッド・パターンは無視されます。

3. +の接頭辞を付けると、一致するJavaコードのインライン化が強制されます。

4. -の接頭辞を付けると、一致するJavaコードのインライン化が回避されます。

5. オプション: インライン化動作を複数のメソッド・パターンに適用する必要がある場合、これらの手順を繰り返して、複数のinline文を記述します。1つの配列にすべてのパターンを含めないでください。

Examples of inlineディレクティブ・オプションの例を次に示します。

- inline: ["+java/lang*.*", "-sun*.*"]

- inline: "+java/lang*.*"

Enableオプションによる重複の回避

Enableオプションは、ディレクティブの内容を非表示にします。このオプションは、ディレクティブ間の重複を防ぎます。

ディレクティブ・ファイルの例を次に示します。

[
{
match: ["java*.*"],
c1: {
BreakAtExecute: true,
BreakAtCompile: true,
DumpReplay: true,
DumpInline: true,
},
c2: {
MaxNodeLimit: 1000,
},
},
{
match: ["oracle*.*"],
c1: {
BreakAtExecute: true,
BreakAtCompile: true,
DumpReplay: true,
DumpInline: true,
},
c2: {
MaxNodeLimit: 2000,
},
},
]
両方のディレクティブのc1属性は同じものです。この望ましくないコード重複は、Enableオプションで解消されます。Enableは、ブロック・ディレクティブを非表示にし、それらを比較不可とします。解決策の例を次に示します。

[
{
match: ["java*.*"],
c1: {
Enable: false,
},
c2: {
MaxNodeLimit: 1000,
},
},
{
match: ["oracle*.*"],
c1: {
Enable: false,
},
c2: {
MaxNodeLimit: 2000,
},
},
{
match: ["java*.*", "oracle*.*"],
c1: {
BreakAtExecute: true,
BreakAtCompile: true,
DumpReplay: true,
DumpInline: true,
},
c2: {
//Unreachable code
},
},
]
Enableオプションはこのルールに対する例外を示し、一致する最初のディレクティブがメソッドのコンパイルに適用されます。1つ目または2つ目のディレクティブ内のc1によってコンパイルされるメソッドは、3つ目のディレクティブ内のc1ブロックによってコンパイルされるようになりました。3つ目のディレクティブのc2ブロックには到達できません。これは、1つ目および2つ目のディレクティブ内のc2ブロックが優先されるためです。

ディレクティブの理解

次のトピックでは、ディレクティブの動作と相互作用について確認します。

トピック

- デフォルト・ディレクティブとは

- コードへのディレクティブの適用

- コンパイラ・コントロールと下位互換性

デフォルト・ディレクティブとは

デフォルト・ディレクティブは、すべての可能なディレクティブ・オプションのデフォルト値が含まれるコンパイラ・ディレクティブです。これはディレクティブ・スタックの最下部にあり、コンパイルに送信される各メソッドに一致します。

新規ディレクティブを設計する際、新規ディレクティブがデフォルト・ディレクティブとどのように異なるかを指定します。デフォルト・ディレクティブは、設計上の判断を導くためのテンプレートになります。

デフォルト・ディレクティブのディレクティブ・オプション値

空のディレクティブ・スタックを出力すると、デフォルト・ディレクティブの一致基準およびすべてのディレクティブ・オプションの値が明らかになります。

Directive: (default)
matching: *.*
c1 directives:
inline: -
Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000

c2 directives:
inline: -
Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000

注意:
これらの出力ではすべてのディレクティブ・オプションとそれらの値の詳細が提供されますが、特定のオプションはc2コンパイラのみに適用されます。完全なリストについては、表2-2を参照してください。

新規ディレクティブのディレクティブ・オプション値

新規ディレクティブは、それらがデフォルト・ディレクティブとどのように異なるかを指定する必要があります。ディレクティブ・オプションが言及されていない場合、そのオプションはデフォルト・ディレクティブの値を保持します。

次に例を示します。

[
{
match: ["*Concurrent.*"],
c2: {
MaxNodeLimit: 1000,
},
Exclude:true,
},
]
このディレクティブをディレクティブ・スタックに追加すると、デフォルト・ディレクティブはスタック内の最下位のディレクティブになります。この処理の詳細は、ディレクティブ・スタック内のディレクティブの順序を参照してください。最終的なディレクティブ・スタックの出力には、例の中で指定したディレクティブ・オプションのみがデフォルト・ディレクティブにある値と異なっていることが示されます。

Directive:
matching: *Concurrent.*
c1 directives:
inline: -
Enable:true Exclude:true BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000

c2 directives:
inline: -
Enable:true Exclude:true BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:1000

Directive: (default)
matching: *.*
c1 directives:
inline: -
Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000

c2 directives:
inline: -
Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000

コードへのディレクティブの適用

ディレクティブは、メソッド照合プロセスに基づいてコードに適用されます。コンパイルのために送信された各メソッドは、ディレクティブ・スタック内のディレクティブと照合されます。

メソッドとディレクティブ・スタックの照合を行うプロセスはCompilerBrokerによって実行されます。

メソッド照合プロセス

メソッドがコンパイルのために送信されると、その完全修飾名がディレクティブ・スタックの一致基準と比較されます。スタック内の最初の一致ディレクティブがメソッドに適用されます。スタック内の残りのディレクティブは無視されます。それ以外の一致が見つからない場合、デフォルト・ディレクティブが適用されます。

このプロセスは、コンパイルにおいてすべてのメソッドに対して繰り返されます。したがって、コンパイルでは複数のディレクティブが適用される場合があります。ただし、メソッド当たり1つのディレクティブのみが適用されます。スタック内のすべてのディレクティブは潜在的に適用可能であるため、アクティブであるとみなされます。アクティブなディレクティブと適用されたディレクティブの主な違いは次のとおりです。

- ディレクティブがディレクティブ・スタックに存在する場合、そのディレクティブはアクティブです。

- ディレクティブがコードに影響を及ぼしている場合、そのディレクティブは適用されています。

例2-1 一致が見つかった場合

コンパイルのために送信されたメソッドの例:

public int exampleMethod(int x){
return x;
}
メソッド照合基準に基づいて、次の例のディレクティブ・スタックからDirective 2が適用されます。

Directive 2:
matching: *.*example*
Directive 1:
matching: *.*exampleMethod*
Directive 0: (default)
matching: *.*

例2-2 一致が見つからない場合

次の例のメソッドがコンパイルのために送信された場合:

public int otherMethod(int y){
return y;
}
次の例のディレクティブ・スタックのメソッド照合基準に基づいて、Directive 0 (デフォルト・ディレクティブ)が適用されます。

Directive 2:
matching: *.*example*
Directive 1:
matching: *.*exampleMethod*
Directive 0: (default)
matching: *.*

その他のガイドライン

- ディレクティブのメソッド照合基準を慎重に記述します。指定されたメソッドに適用されるディレクティブを検証するフィードバック・メカニズムはありません。かわりに、JMXなどのプロファイラを使用して、適用されたディレクティブの累積的な影響を測定できます。

- CompilerBrokerは、不正なコード(対応していないプラットフォームのハードウェアに命令を強制するなど)を作成するディレクティブ・オプションを無視します。警告メッセージが表示されます。

- ディレクティブ・オプションには、一般的なコマンドライン・フラグと同じ制限があります。たとえば、インライン・コードに対する命令が処理されるのは、中間表現(IR)が大きくなりすぎない場合にかぎられます。

コンパイラ・コントロールと下位互換性

コンパイラ・コントロール・ディレクティブとともに、CompileCommandおよびコマンドライン・フラグを使用できます。

コンパイラ・コントロールはすべてのユース・ケースでCompileCommandを置き換えることができますが、下位互換性は引き続き提供されます。両方を同時に利用することもできます。優先されるのはコンパイラ・コントロールです。競合は、次の優先順位付けに基づいて処理されます。

1. コンパイラ・コントロール

2. CompileCommand

3. コマンドライン・フラグ

4. デフォルト値

例2-3 コンパイラ・コントロールとCompileCommandの併用

次のリストは、いくつかのコンパイル・オプションとこれらのオプションに値を割り当てる方法を示しています。

- コンパイラ・コントロール:

- Exclude: true

- BreakAtExecute: false

- CompileCommand:

- BreakAtExecute: true

- BreakAtCompile: true

- デフォルト値:

- Exclude: false

- BreakAtExecute: false

- BreakAtCompile: false

- Log: false

この例のオプションと値を使用した結果としてのコンパイルへの影響は、下位互換性の競合を処理するルールによって決まります。

- Exclude: true

- BreakAtExecute: false

- BreakAtCompile: true

- Log: false

ディレクティブ・ファイルを操作するためのコマンド

このトピックでは、各種コマンドに加え、作成したディレクティブ・ファイルを操作することによる影響について確認します。

- コンパイラ・ディレクティブとコマンドライン

- コンパイラ・ディレクティブと診断コマンド

- ディレクティブ・スタック内のディレクティブの順序

コンパイラ・ディレクティブとコマンドライン

コマンドラインは、プログラムの起動時にコンパイラ・ディレクティブを追加および出力するインタフェースを提供します。

コマンドラインから指定できるのは、1つのディレクティブ・ファイルのみです。そのファイル内のすべてのディレクティブはディレクティブ・スタックに追加され、プログラムが起動すると即座にアクティブになります。これにより、プログラムの初期段階にディレクティブのパフォーマンスの影響をテストできます。また、プログラムのデバッグと開発に集中することもできます。

コマンドラインからのディレクティブの追加

ディレクティブ・ファイルを指定するコマンドライン・オプションは次のとおりです。

XX:CompilerDirectivesFile=file
このコマンドライン・オプションは、Javaプログラムを起動する際に含めます。これを次の例に示します(TestProgramを起動する例)。

java -XX:+UnlockDiagnosticVMOptions -XX:CompilerDirectivesFile=File_A.json TestProgram

- -XX:+UnlockDiagnosticVMOptionsは、診断オプションを有効にします。これは、コマンドラインでディレクティブを操作する前に入力してください。

- -XX:CompilerDirectivesFileは、診断オプションのタイプです。ディレクティブ・スタックに追加するディレクティブ・ファイルを1つ指定します。

- File_A.jsonは、ディレクティブ・ファイルです。これには任意の数のディレクティブが含まれ、それらすべてがプログラムの起動時にディレクティブ・スタックに追加されます。

- File_A.jsonに構文エラーまたは不正なディレクティブがある場合はエラー・メッセージが表示され、TestProgramは起動されません。

コマンドラインからのディレクティブの出力

プログラムの起動時、または診断コマンドから別のディレクティブが追加された場合に、ディレクティブ・スタックを自動的に出力できます。この動作を有効にするコマンドライン・オプションは次のとおりです。

-XX:+CompilerDirectivesPrint
この診断コマンドをコマンドラインに含める例を次に示します。

java -XX:+UnlockDiagnosticVMOptions -XX:+CompilerDirectivesPrint -XX:CompilerDirectivesFile=File_A.json TestProgram

コンパイラ・ディレクティブと診断コマンド

診断コマンドは、実行時にアクティブになるディレクティブを管理するインタフェースを提供します。実行中のプログラムに対するディレクティブの追加と削除をプログラムの再起動なしで行うことができます。

1つの完全なディレクティブ・ファイルを作成するには、なんらかの反復と実験が必要になることがあります。しかし、診断コマンドには、ディレクティブ・スタック内のディレクティブの異なる構成をテストするための強力なメカニズムが用意されています。診断コマンドを使用すると、実行中のプログラムのJVMを再起動することなく、ディレクティブの追加や削除を行うことができます。

Javaプロセス識別番号の取得

ディレクティブをテストするための最初の手順は、実行中のプログラムのプロセス識別(pid)番号を特定することです。

1. ターミナルを開きます。

2. jcmdと入力します。

このコマンドは、マシン上で実行されている各Javaプロセスとそのpid番号のリストを返します。たとえば、TestProgramについて次のような情報が返されます。

11084 TestProgram

診断コマンドによるディレクティブの追加

ファイル内のすべてのディレクティブは、1つの診断コマンドを介してディレクティブ・スタックに追加されます。

次のように入力します。

jcmd pid Compiler.directives_add file
次に例を示します。

jcmd 11084 Compiler.directives_add File_B.json
ターミナルは、追加された個々のディレクティブの数を報告します。ただし、ディレクティブ・ファイルに構文エラーまたは不正なディレクティブがある場合はエラー・メッセージが表示され、ファイル内のディレクティブはスタックに追加されません。実行中のプログラムに変更はありません。

診断コマンドによるディレクティブの削除

ディレクティブを削除する診断コマンドは2つあります。

ディレクティブ・スタックから最上位のディレクティブを1つ削除するには、次のように入力します。

jcmd pid Compiler.directives_remove
追加したディレクティブをディレクティブ・スタックから消去するには、次のように入力します。

jcmd pid Compiler.directives_clear
ファイル全体のディレクティブを指定して削除することや、ディレクティブをまとめて削除することはできません。

診断コマンドによるディレクティブの出力

実行中のプログラムのディレクティブ・スタックを出力するには、診断コマンドを使用します。

次のように入力するたびに、ディレクティブ・スタック全体の詳細な説明が出力されます。

jcmd pid Compiler.directives_print
出力の例は、デフォルト・ディレクティブとはに示されています。

ディレクティブ・スタック内のディレクティブの順序

ディレクティブをファイルに書き込む順序、スタックに追加する順序は非常に重要です。スタック内の最上位にある一致度の高いディレクティブが優先され、コードのコンパイルに適用されます。

このトピックの図は、ディレクティブ・スタックの例における順序の影響を示しています。このシナリオには、次の3つのディレクティブ・ファイルがあります。

- File_Aには、Directive 1とDirective 2が含まれます。

- File_Bには、Directive 3が含まれます。

- File_Cには、Directive 4とDirective 5が含まれます。

ディレクティブ・スタックの初期状態

TestProgramは、ディレクティブ・ファイルを使用せずに起動できます。

- ディレクティブを追加せずにプログラムを起動するには、コマンドラインで次のように入力します。

java TestProgram

- TestProgramは、ディレクティブ・ファイルの指定なしで起動します。

- デフォルト・ディレクティブは常にディレクティブ・スタックの最下部にあります。図2-1には、デフォルト・ディレクティブがDirective 0として示されています。ディレクティブ・ファイルを指定しない場合、デフォルト・ディレクティブは最上位のディレクティブとして優先されます。

図2-1 ディレクティブなしのプログラムの起動

別の選択肢として、TestProgramを起動するときに、ディレクティブをディレクティブ・スタックに追加できます。

- File_A.jsonのすべてのディレクティブをディレクティブ・スタックに追加するには、コマンドラインで次のように入力します。

java -XX:+UnlockDiagnosticVMOptions -XX:CompilerDirectivesFile=File_A.json TestProgram

- ディレクティブは、書き込まれた順序とは逆の順序でスタックに追加されます。ファイル内の最上位のディレクティブがスタック内の最上位のディレクティブになります。

- 図2-2は、スタック内のディレクティブの順序が上から順に[1, 2, 0]となることを示しています。

図2-2 ディレクティブありのプログラムの起動

ディレクティブ・スタックへの追加

TestProgramが実行中の場合は、診断コマンドを使用して追加のディレクティブを指定する必要があります。

- File_Bのすべてのディレクティブをディレクティブ・スタックに追加するには、次のように入力します。

jcmd 11084 Compiler.directives_add File_B.json

- Directive 3は、スタックの最上位に追加されます。これは、File_Bにある唯一のディレクティブです。

- 図2-3は、スタック内のディレクティブの順序が[3, 1, 2, 0]となることを示しています。

図2-3 実行中のプログラムへのディレクティブの追加

TestProgramが引き続き実行中であれば、診断コマンドを使用してさらにディレクティブ・ファイルを追加できます。

- File_Cのすべてのディレクティブをディレクティブ・スタックに追加するには、次のように入力します。

jcmd 11084 Compiler.directives_add File_C.json

- 図2-4は、スタック内のディレクティブの順序が[4, 5, 3, 1, 2, 0]となることを示しています。

図2-4 実行中のプログラムへの多数のディレクティブの追加

ディレクティブ・スタックからの削除

最上位のディレクティブは、診断コマンドを使用して削除できます。

- Directive 4をスタックから削除するには、次のように入力します。

jcmd 11084 Compiler.directives_remove

- デフォルト・ディレクティブが残っているかぎり、最上位のディレクティブは1度に1つずつ削除できます。デフォルト・ディレクティブは削除できません。

- 図2-5は、スタック内のディレクティブの順序が[5, 3, 1, 2, 0]となることを示しています。

図2-5 スタックからの1つのディレクティブの削除

ディレクティブ・スタックからディレクティブを一括削除するメカニズムが1つあります。

- ディレクティブ・スタックを消去するには、次のように入力します。

jcmd 11084 Compiler.directives_clear

- デフォルト・ディレクティブを除くすべてのディレクティブが1度に削除されます。デフォルト・ディレクティブは削除できません。

- 図2-6は、Directive 0のみがスタック内に残っていることを示しています。

図2-6 スタックからのすべてのディレクティブの削除

3 ガベージ・コレクション

Java HotSpot VMには、アプリケーションのパフォーマンスを最適化するために使用できる、いくつかのガベージ・コレクタが含まれています。ガベージ・コレクタは、特に大量のデータ(複数GB)を処理し、多数のスレッドがある、トランザクション率の高いアプリケーションを使用している場合に役立ちます。

使用可能なガベージ・コレクタの詳細は、Java Platform, Standard Edition HotSpot仮想マシン・ガベージ・コレクション・チューニング・ガイドのガベージ・コレクションの実装を参照してください。

4 クラス・データ共有

この章では、Javaアプリケーションの起動時間とメモリー・フットプリントを減らすのに役立つクラス・データ共有(CDS)機能について説明します。

トピック:

- クラス・データ共有の概要

- 共有アーカイブの再生成

- 手動によるクラス・データ共有の制御

クラス・データ共有の概要

クラス・データ共有(CDS)は、複数のJava仮想マシン(JVM)間のデータを動的に共有できるようにします。これにより、起動時間とメモリー・フットプリントを減らすことができます。

インストーラを使用してJREをインストールすると、インストーラがシステムJava Archive (JAR)ファイルから一連のクラスをprivate内部表現にロードして、その表現を共有アーカイブと呼ばれるファイルにダンプします。JREインストーラを使用していない場合は、共有アーカイブを手動で生成できます。

JVMを開始すると、共有アーカイブがメモリー・マッピングされ、これらのクラス用の読取り専用のJVMメタデータを複数のJVM処理で共有できます。共有アーカイブの復元はクラスのロードより速いため、起動時間が短縮され、コストを節約できます。

クラス・データ共有は、G1、シリアル、パラレルおよびparallelOldGCガベージ・コレクタでサポートされています。共有文字列機能(クラス・データ共有の一部)では、64ビットの非Windowsプラットフォーム上のG1ガベージ・コレクタのみがサポートされています。

CDSをJava SEに含める主要な動機は、起動時間の短縮です。使用するコア・クラスの数に比べてアプリケーションが小さいほど、起動時間の節約比率が大きくなります。

新規JVMインスタンスのフットプリント・コストは、2つの方法で削減されています。

1. 同一のホスト上の共有アーカイブの一部が読取り専用としてマップされ、複数のJVM処理で共有されます。それ以外の場合、このデータは各JVMインスタンス内でレプリケートされる必要があるため、アプリケーションの起動時間が長くなります。

2. 共有アーカイブに、Java Hotspot VMが使用できる形式でクラス・データが格納されます。それ以外の場合はランタイム・モジュラ・イメージの元のクラス情報にアクセスするためにメモリーが必要になりますが、この場合は必要ありません。これらの節約により、同じシステム上でより多くのアプリケーションを同時に実行できます。Windowsアプリケーションでは、処理フットプリント(様々なツールで測定)が増えたように見える場合があります。これは、処理のアドレス空間にマッピングされるページが増えるためです。これは、ランタイム・モジュラ・イメージに対して保持する必要があるメモリーの量(Windows内)が減ることによって相殺されます。フットプリントの削減は、依然として優先度の高い課題です。

共有アーカイブの再生成

サポートされているすべてのプラットフォームに対して共有アーカイブを再生成できます。

デフォルトのクラス・リストには、コア・ライブラリ・クラスの小さなセットのみが含まれます。共有アーカイブに他のクラスを含めることもできます。追跡出力をロードしているクラスまたはアプリケーションを実行しているクラスからクラス・リストを作成するには、次のコマンドを入力して、ロードされたすべてのライブラリ・クラスをダンプします。

java -XX:DumpLoadedClassList=<class_list_file>

共有アーカイブを生成するには、プロファイリングに基づいて作成されたクラス・リストを使用する必要があります。

アーカイブ・ファイルは、JVMの共有ライブラリとともに次の場所にあります。

- Solaris、LinuxおよびmacOSプラットフォームの場合、共有アーカイブは/lib/[arch]/server/classes.jsaに格納されます

- Windowsプラットフォームの場合、共有アーカイブは/bin/server/classes.jsaに格納されます

アーカイブ・ファイルが存在する場合、新しいアーカイブ・ファイルを生成すると、既存のファイルが上書きされます。新しいアーカイブを生成する前に古いアーカイブを手動で削除する必要はありません。

アーカイブ・ファイルを再生成するには、管理者としてログインします。ネットワークに接続している場合は、Java SEインストールと同じアーキテクチャのコンピュータにログオンします。インストール・ディレクトリに対する書込み権限を持っていることを確認してください。

ユーザー定義のクラス・リストを使用して共有アーカイブを再生成するには、次のコマンドを入力します。

java -XX:SharedClassListFile=<class_list_file> -Xshare:dump

アーカイブが生成されると、診断情報が出力されます。

手動によるクラス・データ共有の制御

クラス・データ共有機能はデフォルトで有効になっています。この機能は手動で有効と無効を切り替えることができます。

診断およびデバッグのために、次のコマンドライン・オプションを使用できます。

-Xshare:off

クラス・データ共有を無効にします。

-Xshare:on

クラス・データ共有の有効化を要求します。さまざまな理由で有効にできない場合は、エラー・メッセージを出力して終了します。

-Xshare:auto

デフォルト。可能な場合は常にクラス・データ共有を有効にします。

5 Java HotSpot仮想マシン・パフォーマンス向上

この章では、Java HotSpot仮想マシン・テクノロジにおけるパフォーマンスの強化について説明します。

トピック:

- コンパクト文字列

- 階層型コンパイル

- 圧縮Ordinary Object Pointer

- ゼロ・ベース圧縮Ordinary Object Pointer

- エスケープ解析

コンパクト文字列

コンパクト文字列は、文字列の内部表現のスペース効率を高める機能です。

異なるアプリケーションからのデータは、文字列がJavaヒープの使用における主要な構成要素であること、および大半のjava.lang.StringオブジェクトにLatin-1文字のみが含まれていることを示唆しています。そのような文字は、記憶域を1バイトのみ必要とします。結果として、java.lang.Stringオブジェクトの内部文字配列のスペースの半分は使用されません。Java SE 9で採用されたコンパクト文字列機能は、メモリー・フットプリントを削減するだけでなく、ガベージ・コレクション・アクティビティの削減も実現します。アプリケーションでパフォーマンス低下の問題が確認された場合には、この機能を無効にすることができます。

コンパクト文字列機能は、java.lang.Stringクラスの内部表現をUTF-16 (2バイト)文字配列から、文字のエンコードを識別する追加フィールドを含む1バイトの配列に変更します。その他の文字列関連のクラス(AbstractStringBuilder、StringBuilderおよびStringBufferなど)は、同様の内部表現を使用するように更新されます。コンパクト文字列機能は、新たな公開APIまたはインタフェースを採用せず、純粋に文字列の内部表現を変更します。

Java SE 9では、コンパクト文字列機能がデフォルトで有効になっています。したがって、java.lang.Stringクラスは、1文字当たり1バイトとして、Latin-1にエンコードされた文字を格納します。追加の文字エンコード・フィールドは、使用されているエンコードを示します。HotSpot VM文字列の組込みは、内部表現をサポートするように更新および最適化されます。

コンパクト文字列機能は、javaコマンドラインで-XX:-CompactStringsフラグを使用して無効にすることができます。この機能を無効にすると、java.lang.Stringクラスは、UTF-16でエンコードされた文字を2バイトとして格納します。これにより、HotSpot VM文字列の組込みはUTF-16エンコードを使用するように戻されます。

階層型コンパイル

Java SE 7で導入された階層型コンパイルによって、サーバーVMにクライアントVMの起動速度をもたらします。階層型コンパイルなしの場合、サーバーVMはインタプリタを使用して、コンパイラに送信されるメソッドについてのプロファイリング情報を収集します。階層型コンパイルでは、サーバーVMはインタプリタに加えてクライアント・コンパイラを使用して、メソッドのコンパイル・バージョンを生成し、それらが自身のプロファイリング情報を収集します。コンパイルされたコードはインタプリタよりもはるかに高速なため、プログラムのプロファイリング段階の実行パフォーマンスが大きく向上します。サーバー・コンパイラによって生成される最終コードをアプリケーション初期化の早い段階で利用できる可能性があるため、多くの場合クライアントVMの起動速度より起動が速くなります。また、階層型コンパイルではプロファイリング段階の高速化によってプロファイリングにかけられる時間が長くなるため、通常のサーバーVMよりも優れたピーク・パフォーマンスを実現でき、最適化の向上にもつながる可能性があります。

階層型コンパイルはサーバーVMではデフォルトで有効になっています。64ビット・モードおよび圧縮Ordinary Object Pointerがサポートされています。階層型コンパイルを無効にするには、javaコマンドで-XX:-TieredCompilationフラグを使用します。

圧縮Ordinary Object Pointer

Java HotSpotの専門用語であるOrdinary Object Pointer (OOP)は、オブジェクトへの管理ポインタです。OOPは通常、ネイティブ・マシン・ポインタと同じサイズ(LP64システムでは64ビット)です。ILP32システムでは、最大ヒープ・サイズは4Gバイトより少なく、これは多くのアプリケーションにとって十分ではありません。LP64システムでは、指定されたプログラムが使用するヒープが、ILP32システムで実行する場合よりも約1.5倍大きくなることがあります。これほど必要なのは、管理ポインタのサイズが増大することが原因です。メモリーのコストは低いですが、最近では帯域幅およびキャッシュが不足しているため、4Gバイト制限を解決するためだけにヒープ・サイズが大幅に増加するのは望ましくありません。

Javaヒープ内の管理ポインタは、8バイト・アドレス境界に整列されたオブジェクトを指します。圧縮OOPは、(Java仮想マシン(JVM)ソフトウェア内のすべてではないものの多くの場所で)管理ポインタを、64ビットJavaヒープ・ベース・アドレスからの32ビット・オブジェクト・オフセットとして表します。これらはバイト・オフセットではなくオブジェクト・オフセットのため、最大40億のオブジェクト(バイトではありません)、または最大約32Gバイトのヒープ・サイズをアドレス指定するために使用できます。これらを使用して参照先オブジェクトを見つけるには、これらを8倍してJavaヒープ・ベース・アドレスに加算する必要があります。圧縮OOPを使用するオブジェクト・サイズは、ILP32モードのそれに匹敵します。

デコードという語は、32ビット圧縮OOPが64ビット・ネイティブ・アドレスに変換され、管理ヒープ内に追加される処理を表します。エンコードという語は、その逆の処理を表します。

圧縮OOPはJava SE 6u23以降でサポートされ、デフォルトで有効になっています。Java SE 7では、-Xmxが指定されていないときの64ビットJVMプロセスおよび-Xmxの値が32Gバイト未満の場合に、圧縮OOPがデフォルトで有効になります。6u23リリースより前のJDKリリースの場合は、javaコマンドで-XX:+UseCompressedOopsフラグを使用して、圧縮OOPを有効にします。

ゼロ・ベース圧縮Ordinary Object Pointer

64ビットJVMプロセスで圧縮Ordinary Object Pointers (OOP)を使用する場合、JVMソフトウェアは、仮想アドレス・ゼロから始まるメモリーをJavaヒープ用に予約するようにオペレーティング・システムに要求を送信します。オペレーティング・システムがこのような要求をサポートしていて、Javaヒープ用のメモリーを仮想アドレス・ゼロで予約できる場合、ゼロ・ベース圧縮OOPが使用されます。

ゼロ・ベース圧縮OOPを使用する場合、Javaヒープ・ベース・アドレスを含めることなく、32ビット・オブジェクト・オフセットから64ビット・ポインタをデコードできます。ヒープ・サイズが4Gバイト未満の場合、JVMソフトウェアはオブジェクト・オフセットの代わりにバイト・オフセットを使用できるため、オフセットを8倍にすることも回避できます。64ビット・アドレスを32ビット・オフセットにエンコードすると、それだけ効率的になります。

Javaヒープ・サイズが26Gバイトまでの場合は、Solaris、Linux、およびWindowsオペレーティング・システムでは通常、Javaヒープを仮想アドレス・ゼロに割り当てることができます。

エスケープ解析

エスケープ解析は、Java HotSpot Serverコンパイラが新規オブジェクトの使用スコープを解析し、そのオブジェクトをJavaヒープに割り当てるかどうかを決定するための技術です。

エスケープ解析はJava SE 6u23以降でサポートされ、デフォルトで有効になっています。

Java HotSpot Serverコンパイラは、次に記述する、フローインセンシティブ・エスケープ解析アルゴリズムを実装します。

[Choi99] Jong-Deok Choi, Manish Gupta, Mauricio Seffano,
Vugranam C. Sreedhar, Sam Midkiff,
"Escape Analysis for Java", Procedings of ACM SIGPLAN
OOPSLA  Conference, November 1, 1999

エスケープ解析に基づき、オブジェクトのエスケープ状態は次のいずれかになる可能性があります。

- GlobalEscape: オブジェクトはメソッドおよびスレッドをエスケープします。たとえば、staticフィールドに格納された、またはエスケープされたオブジェクトのフィールドに格納された、または現在のメソッドの結果として返されたオブジェクトなど。

- ArgEscape: オブジェクトは引数として渡されるか、または引数によって参照されるけれども、呼出し中にグローバルにエスケープしません。この状態は、呼び出されるメソッドのバイト・コードを解析することで判断されます。

- NoEscape: オブジェクトはスカラー置換可能なオブジェクトです。これは、生成されたコードからその割当てを削除できることを意味します。

エスケープ解析の後、サーバー・コンパイラは、スカラー置換可能オブジェクト割当ておよび関連付けられたロックを、生成されたコードから除去します。また、サーバー・コンパイラはグローバルにエスケープしないオブジェクトのロックも除去します。ヒープ割当てを、グローバルにエスケープしないオブジェクトのスタック割当てで置き換えることはありません。

次の例で、エスケープ解析についていくつかのシナリオを示します。

- サーバー・コンパイラはある種のオブジェクト割り当てを除去する場合があります。たとえば、メソッドがオブジェクトの防衛的コピーを作成してそのコピーを呼出し側に返すとします。

public class Person {
private String name;
private int age;
public Person(String personName, int personAge) {
name = personName;
age = personAge;
}

public Person(Person p) { this(p.getName(), p.getAge()); }
public int getName() { return name; }
public int getAge() { return age; }
}

public class Employee {
private Person person;

// makes a defensive copy to protect against modifications by caller
public Person getPerson() { return new Person(person) };

public void printEmployeeDetail(Employee emp) {
Person person = emp.getPerson();
// this caller does not modify the object, so defensive copy was unnecessary
System.out.println ("Employee's name: " + person.getName() + "; age: "  + person.getAge());
}
}

メソッドは、呼出し側が元のオブジェクトを変更するのを防ぐためにコピーを作成します。コンパイラはgetPersonメソッドがループ内で呼び出されていると判断すると、そのメソッドをインライン化します。コンパイラはエスケープ解析を使用して元のオブジェクトが変更されていないと判断すると、コピーを作成する呼出しを最適化して除去することができます。

- サーバー・コンパイラは、オブジェクトがスレッド・ローカルであると判断すると、同期ブロックを除去する場合があります(ロック除去)。たとえば、StringBufferやVectorなどのクラスのメソッドは、別のスレッドからアクセスできるため同期されています。ただし、ほとんどのシナリオでは、これらはスレッド・ローカルで使用されます。スレッド・ローカルで使用される場合、コンパイラは同期ブロックを最適化して除去することができます。

6 非Java言語のサポート

この章では、Java仮想マシンの非Java言語機能について説明します。

トピック:

- 非Java言語機能の概要

- 静的型付けと動的型付け

- 動的型付け言語のコンパイルの課題

- invokedynamic命令

非Java言語機能の概要

Java Platform, Standard Edition (Java SE)は、次の特徴を持つアプリケーションの開発を可能にします。

- 一度書けば、どこでも実行できる

- Javaサンドボックス・セキュリティ・モデルによって安全に実行できる

- パッケージ化と配信が容易

Java SEプラットフォームは次の領域に対して堅牢なサポートを提供します。

- 同時実行性

- ガベージ・コレクション

- クラスおよびオブジェクトへのリフレクション・ベースのアクセス

- JVM Tool Interface (JVM TI): ツールで使用するためのネイティブ・プログラミング・インタフェース。JVMで実行されるアプリケーションの状態を検査する方法と、その実行を制御する方法の両方を提供します。

OracleのHotSpot JVMは次のツールおよび機能を提供します。

- DTrace: アプリケーションおよびオペレーティング・システムの動作をモニターする動的トレース・ユーティリティ。

- パフォーマンスの最適化

- PrintAssembly: バイト・コード化されたメソッドおよびネイティブ・メソッド用のアセンブリ・コードを出力するJava HotSpotオプション。

Java SE 7プラットフォームは、Java以外の言語でJVMのインフラストラクチャを利用し、パフォーマンスを潜在的に最適化することを可能にします。主要なメカニズムはinvokedynamic命令で、動的型付け言語のコンパイラおよびランタイム・システムのJVMへの実装を簡略化します。

静的型付けと動的型付け

プログラミング言語は、コンパイル時に型チェックを実行する場合、静的に型付けされます。型チェックとは、プログラムが型安全であることを確認する処理のことです。プログラムのすべてのオペレーションの引数が正しい型であれば、そのプログラムは型安全です。

Javaは静的型付け言語です。プログラムがコンパイルされるときに、クラス変数とインスタンス変数、メソッド・パラメータ、戻り値、およびその他の変数の型情報を利用できます。Javaプログラミング言語のコンパイラはこの型情報を使用して強く型付けされたバイト・コードを生成することで、JVMでの実行時に効率的な実行が可能になります。

次のHello Worldプログラムの例は、静的型付けを示しています。型は太字で示しています。

import java.util.Date;

public class HelloWorld {
public static void main(String[] argv) {
String hello = "Hello ";
Date currDate = new Date();
for (String a : argv) {
System.out.println(hello + a);
System.out.println("Today's date is: " + currDate);
}
}
}

プログラミング言語は、実行時に型チェックを実行する場合、動的に型付けされます。JavaScriptとRubyは動的型付け言語の例です。これらの言語は、アプリケーション内の値が予期する型に一致することを、コンパイル時ではなく実行時に確認します。通常、アプリケーションがコンパイルされるときに、これらの言語の型情報は使用できません。オブジェクトの型は実行時にのみ判別されます。以前は、動的型付け言語をJVMに効率よく実装することは困難でした。

次は、Rubyプログラミング言語で記述されたHello Worldプログラムの例です。

#!/usr/bin/env ruby
require 'date'

hello = "Hello "
currDate = DateTime.now
ARGV.each do|a|
puts hello + a
puts "Date and time: " + currDate.to_s
end

この例では、すべての名前が型宣言なしで導入されています。メイン・プログラムはホルダー型(JavaクラスHelloWorld)の中にはありません。RubyでJava forループに相当するものは、動的な型ARGV変数の中にあります。ループの本体は、動的な言語に共通する特徴である、クロージャと呼ばれるブロックに含まれます。

静的型付け言語は強く型付けされた言語であるとはかぎらない

静的型付けプログラミング言語は、強い型付けまたは弱い型付けを使用できます。強い型付けを使用するプログラミング言語は、その操作に提供される値の型に対して制限を指定し、引数に間違った型がある場合に操作を実行できないようにします。弱い型付けを使用する言語は、操作の引数に間違った型または互換性のない型がある場合、これらの引数を暗黙的に変換(キャスト)します。

動的型付け言語は、強い型付けまたは弱い型付けを使用できます。たとえば、Rubyプログラミング言語は動的に、かつ強く型付けされます。変数がなんらかの型の値で初期化されると、Rubyプログラミング言語は変数を別のデータ型に暗黙的に変換しません。

次の例では、Rubyプログラミング言語はFixnum型を持つ数字2を文字列に暗黙的にキャストしません。

a = "40"
b = a + 2

動的型付け言語のコンパイルの課題

2つの数字(どの数値型でも構いません)を追加してその合計を返す、次の動的型付けメソッドaddtwoについて考えます。

def addtwo(a, b)
a + b;
end

あなたの組織が、メソッドaddtwoが記述されたプログラミング言語用のコンパイラとランタイム・システムを実装しているとします。静的型付けか動的型付けかにかかわらず、強く型付けされた言語では、+ (加算演算子)の動作はオペランドの型によって決まります。静的型付け言語のコンパイラは、aおよびbの静的型に基づいて、+の適切な実装を選択します。たとえば、aおよびbの型がintの場合、JavaコンパイラはJVMのiadd命令で+を実装します。JVMのiadd命令は静的に認識されるオペランド型を必要とするため、この加算演算子はメソッド呼出しにコンパイルされます。

動的型付け言語のコンパイラは実行時まで選択を保留する必要があります。文a + bはメソッド呼び出し+(a, b)としてコンパイルされます(+はメソッド名)。JVMでは+という名前のメソッドが許可されますが、Javaプログラミング言語では許可されません。aおよびbが整数型の変数であることを動的型付け言語のランタイム・システムが特定できる場合、ランタイム・システムは、任意のオブジェクト型ではなく、整数型に特化した+の実装を呼び出します。

動的型付け言語のコンパイルの課題は、プログラムがコンパイルされた後に、メソッドまたは関数の最適な実装を選択できるランタイム・システムをどのように実装するかです。すべての変数をObject型のオブジェクトとして扱うと効率的に機能しません。これは、Objectクラスに+という名前のメソッドが含まれていないためです。

Java SE 7以降では、invokedynamic命令によって、ランタイム・システムがコール・サイトとメソッド実装との間のリンケージをカスタマイズできます。この例では、invokedynamicコール・サイトは+です。invokedynamicコール・サイトは、ブートストラップ・メソッド (サイトをリンクするためにJVMによって1回呼び出される、動的型付け言語のコンパイラによって指定されるメソッド)によって、メソッドにリンクされます。+を呼び出すinvokedynamic命令をコンパイラが発行したと想定し、かつランタイム・システムがメソッドadder(Integer,Integer)を認識すると想定したうえで、ランタイムは次のようにinvokedynamicコール・サイトをadderメソッドにリンクできます。

IntegerOps.java

class IntegerOps {

public static Integer adder(Integer x, Integer y) {
return x + y;
}
}

Example.java

import java.util.*;
import java.lang.invoke.*;
import static java.lang.invoke.MethodType.*;
import static java.lang.invoke.MethodHandles.*;

class Example {

public static CallSite mybsm(
MethodHandles.Lookup callerClass, String dynMethodName, MethodType dynMethodType)
throws Throwable {

MethodHandle mh =
callerClass.findStatic(
Example.class,
"IntegerOps.adder",
MethodType.methodType(Integer.class, Integer.class, Integer.class));

if (!dynMethodType.equals(mh.type())) {
mh = mh.asType(dynMethodType);
}

return new ConstantCallSite(mh);
}
}

この例では、IntegerOpsクラスは動的型付け言語のランタイム・システムに付属のライブラリに属します。

Example.mybsmメソッドは、invokedynamicコール・サイトをadderメソッドにリンクするブートストラップ・メソッドです。

callerClassオブジェクトはlookupオブジェクト(メソッド・ハンドルを作成するためのファクトリ)です。

MethodHandles.Lookup.findStaticメソッド(callerClass lookupオブジェクトから呼び出される)は、メソッドadderの静的メソッド・ハンドルを作成します。

注意: このブートストラップ・メソッドは、adderメソッドで定義されたコードのみにinvokedynamicコール・サイトをリンクします。このメソッドは、invokedynamicコール・サイトに指定された引数がIntegerオブジェクトであることを前提としています。ブートストラップ・メソッドは、ブートストラップ・メソッドのパラメータ(この例ではcallerClass、dynMethodName、およびdynMethodType)が変化すると実行されるコードにinvokedynamicコール・サイトを正しくリンクするために、追加コードを必要とします。

java.lang.invoke.MethodHandlesクラスおよびjava.lang.invoke.MethodHandleクラスには、既存のメソッド・ハンドルに基づいてメソッド・ハンドルを作成する様々なメソッドが含まれています。この例では、mhメソッド・ハンドルのメソッド・タイプがdynMethodTypeパラメータで指定されたメソッド・タイプと一致しない場合に、asTypeメソッドを呼び出します。これにより、ブートストラップ・メソッドはinvokedynamicコール・サイトをメソッド・タイプが厳密に一致しないJavaメソッドにリンクできます。

ブートストラップ・メソッドによって返されるConstantCallSiteインスタンスは、個々のinvokedynamic命令に関連付けられているコール・サイトを表します。ConstantCallSiteインスタンスのターゲットは永続的で変更できません。この場合、1つのJavaメソッドadderがコール・サイト実行の候補です。このメソッドはJavaメソッドでなくてもかまいません。かわりに、ランタイム・システムで使用できるこのようなメソッドがいくつかあり、それぞれが異なる引数型を処理する場合、mybsmブートストラップ・メソッドは、dynMethodType引数に基づいて正しいメソッドを動的に選択できます。

invokedynamic命令

invokedynamicは、動的言語のコンパイラおよびランタイム・システムのJVM上への実装を簡略化し、潜在的に改善します。invokedynamic命令を使用すると、言語実装者はカスタム・リンケージを定義できます。この点は、invokevirtualなどその他のJVM命令とは異なります(Javaクラスおよびインタフェースに固有のリンケージ動作がJVMによって固定されている)。

invokedynamic命令の各インスタンスは動的コール・サイトと呼ばれます。動的コール・サイトのインスタンスが作成されると、そのサイトはリンクされていない状態になり、呼び出すコール・サイトにはメソッドが指定されていません。動的コール・サイトは、ブートストラップ・メソッドによってメソッドにリンクされます。動的コール・サイトのブートストラップ・メソッドは、動的型付け言語のコンパイラによって指定されるメソッドです。メソッドはJVMによって1回呼び出され、サイトにリンクされます。ブートストラップ・メソッドから返されるオブジェクトは、コール・サイトのアクティビティを永続的に決定します。

invokedynamic命令には、定数プール・インデックス(その他のinvoke命令と同じ形式)が含まれます。定数プール・インデックスはCONSTANT_InvokeDynamicエントリを参照します。このエントリは、ブートストラップ・メソッド(CONSTANT_MethodHandleエントリ)、動的にリンクされるメソッドの名前、および動的にリンクされるメソッドへの呼出しの引数の型と戻り型を指定します。

次の例では、ランタイム・システムがExample.mybsmブートストラップ・メソッドを使用することで、invokedynamic命令(+、加算演算子)で指定された動的コール・サイトをIntegerOps.adderメソッドにリンクします。adderメソッドおよびmybsmメソッドは、動的型付け言語のコンパイルの課題で定義されています(わかりやすくするために改行が追加されています)。

invokedynamic   InvokeDynamic
REF_invokeStatic:
Example.mybsm:
"(Ljava/lang/invoke/MethodHandles/Lookup;
Ljava/lang/String;
Ljava/lang/invoke/MethodType;)
Ljava/lang/invoke/CallSite;":
+:
"(Ljava/lang/Integer;
Ljava/lang/Integer;)
Ljava/lang/Integer;";

注意:
バイト・コード例は、ASM Javaバイト・コード操作および分析フレームワークの構文を使用しています。

動的にリンクされるメソッドをinvokedynamic命令で呼び出すには、次の手順が必要です。

1. ブートストラップ・メソッドを定義する

2. 定数プール・エントリを指定する

3. invokedynamic命令を使用する

ブートストラップ・メソッドを定義する

実行時に、JVMが初めてinvokedynamicを検出すると、ブートストラップ・メソッドが呼び出されます。このメソッドは、invokedynamic命令で指定された名前を、ターゲット・メソッドを実行するコード(メソッド・ハンドルによって参照される)にリンクします。JVMが同じinvokedynamic命令を再度実行する場合、ブートストラップ・メソッドを呼び出さず、リンクされたメソッド・ハンドルを自動的に呼び出します。

ブートストラップ・メソッドの戻り型はjava.lang.invoke.CallSiteである必要があります。CallSiteオブジェクトは、invokedynamic命令とそれがリンクされるメソッド・ハンドルのリンク状態を表します。

ブートストラップ・メソッドは、次のパラメータを3つ以上取ります。

- MethodHandles.Lookupオブジェクト: invokedynamic命令のコンテキスト内でメソッド・ハンドルを作成するファクトリ。

- Stringオブジェクト: 動的コール・サイト内で言及されるメソッド名。

- MethodTypeオブジェクト: 動的コール・サイトの解決済型シグニチャ。

- invokedynamic命令に対する1つ以上の追加の静的引数: 定数プールから取り出されるオプションの引数の目的は、言語実装者がブートストラップ・メソッドに便利な追加メタデータを安全かつコンパクトにエンコードするのを支援することです。各コール・サイトには独自のブートストラップ・メソッドが指定される可能性があるため、原則として名前と追加引数は冗長になります。ただし、そのような運用ではおそらく、大きなクラス・ファイルや定数プールが生成されます。

ブートストラップ・メソッドの例については、動的型付け言語のコンパイルの課題を参照してください。

定数プール・エントリを指定する

invokedynamic命令には、CONSTANT_InvokeDynamicタグを持つ定数プール内のエントリへの参照が含まれます。このエントリには、定数プール内のその他のエントリへの参照および属性への参照が含まれます。java.lang.invokeパッケージのドキュメントおよびJava仮想マシン仕様を参照してください。

定数プールの例

次の例は、メソッド+をJavaメソッドadderにリンクするブートストラップ・メソッドExample.mybsmを含む、クラスExampleの定数プールからの引用です。

class #159; // #47
Utf8 "adder"; // #83
Utf8 "(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;"; // #84
Utf8 "mybsm"; // #87
Utf8 "(Ljava/lang/invoke/MethodHandles/Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)
java/lang/invoke/CallSite;"; // #88
Utf8 "Example"; // #159
Utf8 "+"; // #166

// ...

NameAndType #83 #84; // #228
Method #47 #228; // #229
MethodHandle 6b #229; // #230
NameAndType #87 #88; // #231
Method #47 #231; // #232
MethodHandle 6b #232; // #233
NameAndType #166 #84; // #234
Utf8 "BootstrapMethods"; // #235
InvokeDynamic 0s #234; // #236

この例のinvokedynamic命令の定数プール・エントリには、3つの値が含まれています。

- CONSTANT_InvokeDynamicタグ

- 符号なしshort値0

- 定数プール・インデックス#234。

値0は、BootstrapMethods属性に格納されている指定子配列内の最初のブートストラップ・メソッド指定子を参照します。ブートストラップ・メソッド指定子は定数プール表に含まれていません。それらはこの個別の指定子配列に含まれています。各ブートストラップ・メソッド指定子にはCONSTANT_MethodHandle定数プール・エントリ(ブートストラップ・メソッドそのもの)へのインデックスが含まれています。

次の例は、BootstrapMethods属性を示す、同じ定数プールからの引用で、ブートストラップ・メソッド指定子の配列が含まれています。

[3] { // Attributes

// ...

Attr(#235, 6) { // BootstrapMethods at 0x0F63
[1] { // bootstrap_methods
{  //  bootstrap_method
#233; // bootstrap_method_ref
[0] { // bootstrap_arguments
}  //  bootstrap_arguments
}  //  bootstrap_method
}
} // end BootstrapMethods
} // Attributes

ブートストラップ・メソッドmybsmのメソッド・ハンドルの定数プール・エントリには次の値が含まれています。

- CONSTANT_MethodHandleタグ

- 符号なしbyte値6

- 定数プール・インデックス#232。

値6はREF_invokeStaticサブタグです。このサブタグの詳細は、次のセクションinvokedynamic命令を使用するを参照してください。

invokedynamic命令を使用する

次の例は、バイト・コードがinvokedynamic命令を使用して、動的コール・サイト(+、加算演算子)をadderメソッドにリンクするmybsmブートストラップ・メソッドを呼び出す方法を示しています。この例では、+メソッドを使用して数字40と2を追加しています(わかりやすくするために改行が挿入されています)。

bipush  40;
invokestatic    Method java/lang/Integer.valueOf:"(I)Ljava/lang/Integer;";
iconst_2;
invokestatic    Method java/lang/Integer.valueOf:"(I)Ljava/lang/Integer;";
invokedynamic   InvokeDynamic
REF_invokeStatic:
Example.mybsm:
"(Ljava/lang/invoke/MethodHandles/Lookup;
Ljava/lang/String;
Ljava/lang/invoke/MethodType;)
Ljava/lang/invoke/CallSite;":
+:
"(Ljava/lang/Integer;
Ljava/lang/Integer;)
Ljava/lang/Integer;";

最初の4つの命令は、整数40と2をスタック上に置き、それらをjava.lang.Integerラッパー型にAutoboxingします。5つ目の命令が動的メソッドを呼び出します。この命令は、CONSTANT_InvokeDynamicタグを持つ定数プール・エントリを参照します。

REF_invokeStatic:
Example.mybsm:
"(Ljava/lang/invoke/MethodHandles/Lookup;
Ljava/lang/String;
Ljava/lang/invoke/MethodType;)
Ljava/lang/invoke/CallSite;":
+:
"(Ljava/lang/Integer;
Ljava/lang/Integer;)
Ljava/lang/Integer;";

このエントリではCONSTANT_InvokeDynamicタグに4つのバイトが続きます。

- 最初の2つのバイトが、ブートストラップ・メソッド指定子を参照するCONSTANT_MethodHandleエントリへの参照を構成しています。

REF_invokeStatic:
Example.mybsm:
"(Ljava/lang/invoke/MethodHandles/Lookup;
Ljava/lang/String;
Ljava/lang/invoke/MethodType;)
Ljava/lang/invoke/CallSite;"

ブートストラップ・メソッド指定子へのこの参照は定数プール表に含まれていません。これはBootstrapMethodsという名前のクラス・ファイル属性によって定義された個別の配列に含まれています。ブートストラップ・メソッド指定子にはCONSTANT_MethodHandle定数プール・エントリ(ブートストラップ・メソッドそのもの)へのインデックスが含まれています。

このCONSTANT_MethodHandle定数プール・エントリには3つのバイトが続きます。

- 最初のバイトはREF_invokeStaticサブタグです。これは、このブートストラップ・メソッドがstaticメソッドのメソッド・ハンドルを作成することを意味します。このブートストラップ・メソッドが動的コール・サイトをstatic Java adderメソッドにリンクしていることに注意してください。

- 次の2つのバイトは、メソッド・ハンドル作成対象のメソッドを表す、CONSTANT_Methodrefエントリを構成しています。

Example.mybsm:
"(Ljava/lang/invoke/MethodHandles/Lookup;
Ljava/lang/String;
Ljava/lang/invoke/MethodType;)
Ljava/lang/invoke/CallSite;"

この例では、ブートストラップ・メソッドの完全修飾名はExample.mybsmです。引数型はMethodHandles.Lookup、StringおよびMethodTypeです。戻り型はCallSiteです。

- 次の2つのバイトがCONSTANT_NameAndTypeエントリへの参照を構成しています。

+:
"(Ljava/lang/Integer;
Ljava/lang/Integer;)
Ljava/lang/Integer;"

この定数プール・エントリは、メソッド名(+)、引数型(2つのIntegerインスタンス)、および動的コール・サイトの戻り型(Integer)を指定しています。

この例では、動的コール・サイトにはAutoboxingされた整数値(最終ターゲットであるadderメソッドの型に厳密に一致)が渡されます。実際には、引数型と戻り型が厳密に一致する必要はありません。たとえば、invokedynamic命令はJVMスタックにそのオペランドの一方または両方をプリミティブ型int値として渡すことができます。オペランドの一方または両方が型指定のないObject値でもかまいません。invokedynamic命令は、その結果をプリミティブ型int値または型指定のないObject値として受け取ることができます。どの場合も、mybsmのdynMethodType引数がinvokedynamic命令によって要求されるメソッド型を正確に記述します。

adderメソッドに渡されるのは、プリミティブ型でも、型指定のない引数でも、戻り値でもかまいません。ブートストラップ・メソッドが、dynMethodTypeとadderメソッドの型の違いを解決します。コードに示すように、これはターゲット・メソッドでasTypeを呼び出すことで簡単に実行されます。

7 シグナル・チェーン

シグナル・チェーンを使用すると、独自のシグナル・ハンドラをインストールする必要があるアプリケーションを記述できます。この機能は、Solaris、LinuxおよびmacOSで使用できます。

シグナル・チェーン機能には、次の機能があります。

- OracleのHotSpot仮想マシンの作成時に事前インストールされるシグナル・ハンドラに対するサポート。
HotSpot VMが作成されるときに、HotSpot VMで使用されるシグナルのシグナル・ハンドラが保存されます。実行中にこれらのシグナルが生成され、その対象がHotSpot VMでない場合は、事前インストールされたハンドラが呼び出されます。つまり、これらのシグナルのために、事前インストールされたシグナル・ハンドラはHotSpot VMハンドラの背後でチェーンされます。

- HotSpot VM作成後にJava Native Interfaceコード内部または別のネイティブ・スレッドからインストールされるシグナル・ハンドラに対するサポート。
アプリケーションは、libc/libthread/libpthreadライブラリの前にlibjsig.so共有ライブラリをリンクしてロードできます。このライブラリは、HotSpot VMで使用されるシグナル・ハンドラがそのVMによってすでにインストールされたシグナル・ハンドラと競合する場合に、signal()、sigset()、sigaction()などの呼出しを遮断して、それらのシグナル・ハンドラが実際に置き換えられないようにします。かわりに、これらの呼出しは新しいシグナル・ハンドラを保存します。これらのシグナルのために、新しいシグナル・ハンドラはHotSpot VMシグナル・ハンドラの背後でチェーンされます。実行中にこれらのシグナルが生成され、その対象がHotSpot VMでない場合は、事前インストールされたハンドラが呼び出されます。

VMの作成後にインストールされるシグナル・ハンドラに対するサポートが必要ない場合、libjsig.so共有ライブラリは不要です。

シグナル・チェーンを有効にするには、次の手順のいずれかを実行して、libjsig.so共有ライブラリを使用します。

- HotSpot VMを作成するか埋め込むアプリケーションにlibjsig.so共有ライブラリをリンクさせます。

cc -L libjvm.so-directory -ljsig -ljvm java_application.c

- LD_PRELOAD環境変数を使用します。

- Kornシェル(ksh)の場合:

export LD_PRELOAD=libjvm.so-directory/libjsig.so; java_application

- Cシェル(csh)の場合:

setenv LD_PRELOAD libjvm.so-directory/libjsig.so; java_application

この間に呼び出されるsignal()、sigset()およびsigaction()は、HotSpot VMによってインストールされ、オペレーティング・システムで認識されているシグナル・ハンドラではなく、保存されたシグナル・ハンドラを返します。

注意:

SIGQUIT、SIGTERM、SIGINTおよびSIGHUPシグナルはチェーンできません。アプリケーションでこれらのシグナルを処理する必要がある場合は、—Xrsオプションの使用を検討してください。

macOSでのシグナル・チェーンの有効化

macOSでシグナル・チェーンを有効にするには、次の環境変数を設定します。

- DYLD_INSERT_LIBRARIES: SolarisおよびLinuxで、LD_PRELOAD環境変数のかわりに指定されたライブラリを事前ロードします。

- DYLD_FORCE_FLAT_NAMESPACE: macOSの2レベルの名前空間(シンボルの完全修飾名にそのライブラリが含まれる)のために、libjsigライブラリの関数を有効にし、OSの実装を置き換えます。この機能を有効にするには、この環境変数を任意の値に設定します。

次のコマンドを使用して、libjsigライブラリを事前ロードし、シグナル・チェーンを有効にします。

$ DYLD_FORCE_FLAT_NAMESPACE=0 DYLD_INSERT_LIBRARIES="JAVA_HOME/lib/libjsig.dylib" java MySpiffyJavaApp

注意:
macOSのライブラリ・ファイル名はlibjsig.dylibとなり、SolarisまたはLinuxのlibjsig.soとは異なります。

8 ネイティブ・メモリー・トラッキング

この章では、ネイティブ・メモリー・トラッキング(NMT)機能について説明します。NMTは、HotSpot VMの内部メモリー使用状況を追跡するJava HotSpot VM機能です。NMTデータは、jcmdユーティリティを使用してアクセスできます。NMTは、サードパーティ・ネイティブ・コードおよびOracle Java Development Kit (JDK)クラス・ライブラリのメモリー割当てを追跡しません。NMTは、Java Mission Control (JMC)のHotSpotにNMTのMBeanを含めません。

トピック:

- 主な機能

- ネイティブ・メモリー・トラッキングの使用

- NMTの有効化

- jcmdを使用したNMTデータへのアクセス

- VM終了時のNMTデータの取得

主な機能

jcmdでネイティブ・メモリー・トラッキングを使用する場合、Java仮想マシン(JVM)またはHotSpot VMのメモリー使用状況を異なるレベルで追跡できます。NMTは、JVMまたはHotSpot VMが使用するメモリーのみを追跡し、ユーザーのネイティブ・メモリーは追跡しません。NMTは、クラス・データ共有(CDS)アーカイブによって使用されるメモリーの完全な情報は提供しません。

NMTでは次の機能がサポートされています。

- HotSpot VMのNMTは、デフォルトでオフになっています。NMTをオンにするには、JVMコマンドライン・オプションを使用します。高度なランタイム・オプションの詳細は、Java Platform, Standard Editionツール・リファレンスのjavaを参照してください。

- NMTは、jcmdユーティリティを使用してアクセスできます。jcmdを使用したNMTデータへのアクセスを参照してください。jcmdユーティリティを使用してNMTを停止できますが、jcmdユーティリティを使用してNMTを起動または再起動することはできません。

- サマリー・レポートおよび詳細レポートの生成。

- 後の比較のための初期のベースラインの設定。

- JVMコマンドライン・オプションによるJVM終了時のメモリー使用量レポートの要求。「VM終了時のNMT」を参照してください。

ネイティブ・メモリー・トラッキングの使用

NMTデータにアクセスするには、NMTを有効にしてから、jcmdユーティリティを使用する必要があります。

NMTの有効化

NMTを有効にするには、次のコマンドライン・オプションを使用します。

-XX:NativeMemoryTracking=[off | summary | detail]

注意:
NMTを有効にすると、5-10%のパフォーマンス・オーバーヘッドが発生します。

次の表に、NMTコマンドラインの使用オプションを示します。

表8-1 NMTの使用オプション

NMTのオプション

説明

off

NMTはデフォルトでオフになっています。

summary

サブシステム別に集約されたメモリー使用量のみ収集します。

detail

個々のコール・サイト別のメモリー使用量を収集します。

jcmdを使用したNMTデータへのアクセス

jcmdを使用して収集したデータをダンプし、必要に応じて、そのデータを最後のベースラインと比較します。

jcmd <pid> VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] [scale= KB | MB | GB]

表8-2 jcmdのNMTオプション

jcmdのNMTオプション

説明

summary

カテゴリ別に集約されたサマリーを出力します。

detail

- カテゴリ別に集約されたメモリー使用量の出力

- 仮想メモリー・マップの出力

- コール・サイト別に集約されたメモリー使用量の出力

baseline

比較のために新しいメモリー使用量スナップショットを作成します。

summary.diff

最後のベースラインに照らして新しいサマリー・レポートを出力します。

detail.diff

最後のベースラインに照らして新しい詳細レポートを出力します。

shutdown

NMTを停止します。

VM終了時のNMTデータの取得

ネイティブ・メモリー・トラッキングが有効になっている場合、VMの終了時に最後のメモリー使用量のデータを取得するには、次のVM診断コマンドライン・オプションを使用します。詳細レベルは、トラッキング・レベルに基づいています。

-XX:+UnlockDiagnosticVMOptions -XX:+PrintNMTStatistics

VMの内部メモリー割当てをモニターし、VMのメモリー・リークを診断する方法は、Java Platform, Standard Editionトラブルシューティング・ガイドのネイティブ・メモリー・トラッキングを参照してください。

9 HotSpot VM内のDTraceプローブ

この章では、OracleのHotSpot VMにおけるDTraceのサポートについて説明します。hotspotおよびhotspot_jniプロバイダはJVMの内部状態、アクティビティ、および実行中のJavaアプリケーションをモニターするために使用されるプローブを利用可能にします。プローブはすべてUSDTプローブであり、JVMプロセスのプロセスIDを使用してアクセスされます。

トピック:

- hotspotプロバイダの使用

- VMライフサイクル・プローブ

- スレッド・ライフサイクル・プローブ

- クラス・ロード・プローブ

- ガベージ・コレクション・プローブ

- メソッド・コンパイル・プローブ

- モニター・プローブ

- アプリケーション追跡プローブ

- hotspot_jniプロバイダの使用

- サンプルDTraceプローブ

hotspotプロバイダの使用

hotspotプロバイダはVMの存続期間、スレッドの開始および終了イベント、ガベージ・コレクタ(GC)およびメモリー・プール統計、メソッド・コンパイル、ならびにモニター活動の追跡に使用できるプローブを利用可能にします。起動フラグにより、メソッドに入るプローブやメソッドから戻るプローブなどの実行中のJavaプログラム、およびオブジェクト割当てのモニターに使用できる追加プローブが有効になります。hotspotプローブはVMライブラリ(libjvm.so)を基準にしているため、VMが埋め込まれたプログラムから提供されます。

プロバイダ内のプローブの多くには、VMの状態に関する詳細を提供する引数があります。これらの引数の多くは、プローブ起動を相互にリンクするために使用できる不透明なIDです。ただし、文字列などのデータも提供されます。文字列値が提供される場合、それらは常に、終了されていない変更されたUTF-8データ(JVM仕様を参照)へのポインタとそのデータの範囲を示す長さの値のペアです。文字列データは(ASCIIの範囲外の文字がない場合でも) NUL文字で終了されている保証はないため、長さで終了されるcopyinstr()組込みを使用して、文字列データを読み取る必要があります。

VMライフサイクル・プローブ

VMライフサイクル・アクティビティの追跡には、次のプローブを使用できます。いずれも引数は取りません。

表9-1 VMライフサイクル・プローブ

プローブ

説明

vm-init-begin

VM初期化が開始されるときに起動するプローブ

vm-init-end

VM初期化が終了するときに起動するプローブで、VMはアプリケーション・コードの実行を開始する準備ができています

vm-shutdown

プログラム終了またはエラーによってVMがシャットダウンするときに起動するプローブ

スレッド・ライフサイクル・プローブ

スレッドの開始および終了イベントの追跡には、次のプローブを使用できます。

プローブ

説明

thread-start

スレッドが開始されるときに起動するプローブ。

thread-stop

スレッドが完了したときに起動するプローブ。

スレッド・ライフサイクル・プローブには、次の引数を使用できます。

プローブの引数

説明

args[0]

スレッド名を含むUTF-8文字列データへのポインタ

args[1]

スレッド名データの長さ(バイト単位)

args[2]

JavaスレッドID。この値はスレッド引数を含む他のHotSpot VMプローブに対応します

args[3]

ネイティブ/OSスレッドID。このIDはホスト・オペレーティング・システムによって割り当てられます

args[4]

このスレッドがデーモンかどうかを示すブール値。値0は、デーモン以外のスレッドを示します

クラス・ロード・プローブ

クラスのロードおよびアンロード・アクティビティの追跡には、次のプローブを使用できます。

プローブ

説明

class-loaded

クラスがロードされたときに起動するプローブ

class-unloaded

クラスがシステムからアンロードされたときに起動するプローブ

クラス・ロード・プローブには、次の引数を使用できます。

プローブの引数

説明

args[0]

ロードされたクラスの名前を含むUTF-8文字列データへのポインタ

args[1]

クラス名データの長さ(バイト単位)

args[2]

クラス・ローダーID。VM内のクラス・ローダーの一意の識別子です。(これは、クラスをロードしたクラス・ローダーです)

args[3]

クラスが共有クラスかどうか(クラスが共有アーカイブからロードされたかどうか)を示すブール値

ガベージ・コレクション・プローブ

システム全体のガベージ・コレクション・サイクルの期間を測定するために使用できるプローブがあります(開始および終了が定義されているガベージ・コレクタについて)。各メモリー・プールは個別に追跡されます。プール・コレクションの開始と終了の両方で、個々のプールのプローブはメモリー・マネージャの名前、プール名、およびプール使用状況の情報を渡します。

ガベージ・コレクション・アクティビティの追跡には、次のプローブを使用できます。

プローブ

説明

gc-begin

システム全体のコレクションが開始されるときに起動するプローブ。このプローブに使用できる1つの引数(arg[0])は、フルGCを実行するかどうかを示すブール値です。

gc-end

システム全体のコレクションが完了したときに起動するプローブ。引数はありません。

mem-pool-gc-begin

個々のメモリー・プールが収集されるときに起動するプローブ。

mem-pool-gc-end

個々のメモリー・プールが収集された後で起動するプローブ。

メモリー・プール・プローブには、次の引数を使用できます。

プローブの引数

説明

args[0]

このメモリー・プールを管理するマネージャの名前を含むUTF-8文字列データへのポインタ

args[1]

マネージャ名データの長さ(バイト単位)

args[2]

メモリー・プールの名前を含むUTF-8文字列データへのポインタ

args[3]

メモリー・プール名データの長さ(バイト単位)

args[4]

メモリー・プールの初期サイズ(バイト単位)

args[5]

メモリー・プール内の使用中のメモリー量(バイト単位)

args[6]

メモリー・プール内のコミット済みページ数

args[7]

メモリー・プールの最大サイズ

メソッド・コンパイル・プローブ

どのメソッドがどのコンパイラによってコンパイルされているかを示すために、およびコンパイルされたメソッドがインストールまたはアンインストールされたときを追跡するために、プローブを使用できます。

メソッド・コンパイルの開始および終了を示すために、次のプローブを使用できます。

プローブ

説明

method-compile-begin

メソッド・コンパイルが開始されるときに起動するプローブ。

method-compile-end

メソッド・コンパイルが完了したときに起動するプローブ。次の引数に加え、argv[8]引数はコンパイルが成功したかどうかを示すブール値です。

メソッド・コンパイル・プローブには、次の引数を使用できます。

プローブの引数

説明

args[0]

このメソッドをコンパイルしているコンパイラの名前を含むUTF-8文字列データへのポインタ

args[1]

コンパイラ名データの長さ(バイト単位)

args[2]

コンパイルされているメソッドのクラスの名前を含むUTF-8文字列データへのポインタ

args[3]

クラス名データの長さ(バイト単位)

args[4]

コンパイルされているメソッドの名前を含むUTF-8文字列データへのポインタ

args[5]

メソッド名データの長さ(バイト単位)

args[6]

コンパイルされているメソッドのシグニチャを含むUTF-8文字列データへのポインタ

args[7]

シグニチャ・データの長さ(バイト単位)

コンパイルされたメソッドが実行用にインストールまたはアンインストールされるときに、次のプローブを使用できます。

プローブ

説明

compiled-method-load

コンパイルされたメソッドがインストールされるときに起動するプローブ。その他の引数として、argv[6]にはコンパイルされたコードへのポインタが含まれ、argv[7]はコンパイルされたコードのサイズです。

compiled-method-unload

コンパイルされたメソッドがアンインストールされるときに起動するプローブ。

コンパイルされたメソッドのロード・プローブには、次の引数を使用できます。

プローブの引数

説明

args[0]

インストールされているメソッドのクラスの名前を含むUTF-8文字列データへのポインタ

args[1]

クラス名データの長さ(バイト単位)

args[2]

インストールされているメソッドの名前を含むUTF-8文字列データへのポインタ

args[3]

メソッド名データの長さ(バイト単位)

args[4]

インストールされているメソッドのシグニチャを含むUTF-8文字列データへのポインタ

args[5]

シグニチャ・データの長さ(バイト単位)

モニター・プローブ

Javaアプリケーションが実行されるとき、スレッドはモニターへの出入り、モニターでの待機、および通知を実行します。プローブは、すべての待機イベントおよび通知イベントに使用できます。また、競合するモニターに入るイベントおよびモニターから出るイベントにも使用できます。

競合するモニターに入るイベントは、別のスレッドがモニター内にあるときに、スレッドがモニターに入ろうとする場合に発生します。競合するモニターから出るイベントは、スレッドがモニターから出るときに、他のスレッドがモニターに入るのを待機している場合に発生します。競合するモニターに入るイベントと競合するモニターから出るイベントは、これらのイベントに遭遇する1つのスレッドについては一致しませんが、競合するスレッドから出るイベントは、競合する別のスレッド(モニターに入るのを待機しているスレッド)に入るイベントと一致すると考えられます。

モニター・イベントはスレッドID、モニターID、およびオブジェクトのクラスのタイプを引数として提供します。スレッドIDおよびクラスは、Javaプログラムへマッピングで戻ることができます。一方、モニターIDはプローブ起動間の一致情報を提供できます。

VM内にこれらのプローブが存在することによってパフォーマンスが低下するので、これらはjavaコマンドラインで-XX:+ExtendedDTraceProbesフラグが設定された場合にのみ起動します。このフラグは、jinfoユーティリティを使用することによって、実行時に動的にオンおよびオフにできます。

フラグがオフの場合、モニター・プローブはDtraceから取得可能なプローブ・リストに存在しますが、プローブは休止状態であり起動しません。この制限は、VMの今後のリリースでは削除される予定です。これらのプローブは、パフォーマンスに影響を与えることなく有効になる予定です。

イベントのモニターには、次のプローブを使用できます。

プローブ

説明

monitor-contended-enter

競合するモニターにスレッドが入ろうとしたときに起動するプローブ

monitor-contended-entered

競合するモニターにスレッドが正常に入るときに起動するプローブ

monitor-contended-exit

あるスレッドがモニターを出るときに、他のスレッドが入るのを待機している場合に起動するプローブ

monitor-wait

Object.wait()を使用してスレッドがモニターで待機を開始するときに起動するプローブ。追加の引数args[4]は、使用されるタイムアウトを示すlong値です。

monitor-waited

スレッドがObject.wait()アクションを完了するときに起動するプローブ

monitor-notify

スレッドがObject.notify()を呼び出してモニターでの待機者に通知するときに起動するプローブ

monitor-notifyAll

スレッドがObject.notifyAll()を呼び出してモニターでの待機者に通知するときに起動するプローブ

モニターには、次の引数を使用できます。

プローブの引数

説明

args[0]

モニター・オペレーションを実行するスレッドのJavaスレッド識別子

args[1]

アクションが実行される特定のモニターの一意だが不透明な識別子

args[2]

アクションが実行されているオブジェクトのクラス名を含むUTF-8文字列データへのポインタ

args[3]

クラス名データの長さ(バイト単位)

アプリケーション追跡プローブ

Javaスレッド実行を精査するためのプローブを使用できます。アプリケーション追跡プローブは、メソッドに入るときやメソッドから戻るとき、およびJavaオブジェクトが割り当てられたときに起動します。

VM内にこれらのプローブが存在することによってパフォーマンスが低下するので、これらはVMでExtendedDTraceProbesフラグが有効な場合にのみ起動します。デフォルトでは、プローブはVM内のプローブのリストに存在しますが、適切なフラグが立っていない場合は休止状態です。この制限は、VMの今後のリリースでは削除される予定です。これらのプローブは、パフォーマンスに影響を与えることなく有効になる予定です。

メソッドの出入りには、次のプローブを使用できます。

プローブ

説明

method-entry

メソッドに入っているときに起動するプローブ。

method-return

正常に、または例外によって、メソッドから戻るときに起動するプローブ。

メソッドの出入りには、次の引数を使用できます。

プローブの引数

説明

args[0]

メソッドに入る、またはメソッドを出るスレッドのJavaスレッドID

args[1]

メソッドのクラスの名前を含むUTF-8文字列データへのポインタ

args[2]

クラス名データの長さ(バイト単位)

args[3]

メソッドの名前を含むUTF-8文字列データへのポインタ

args[4]

メソッド名データの長さ(バイト単位)

args[5]

メソッドのシグニチャを含むUTF-8文字列データへのポインタ

args[6]

シグニチャ・データの長さ(バイト単位)

オブジェクト割当てには、次のプローブを使用できます。

プローブ

説明

object-alloc

ExtendedDTraceProbesフラグが有効な場合、オブジェクトが割り当てられたときに起動するプローブ。

オブジェクト割当てプローブには、次の引数を使用できます。

プローブの引数

説明

args[0]

オブジェクトを割り当てているスレッドのJavaスレッドID

args[1]

割り当てられているオブジェクトのクラス名を含むUTF-8文字列データへのポインタ

args[2]

クラス名データの長さ(バイト単位)

args[3]

割り当てられているオブジェクトのサイズ

hotspot_jniプロバイダの使用

ネイティブ・コードからJavaコードを呼び出す場合、アプリケーションへのVMの埋込みやJavaアプリケーション内でのネイティブ・コードの実行のため、ネイティブ・コードはJava Native Interface (JNI)インタフェースによって呼出しを行う必要があります。JNIインタフェースは、Javaコードの呼出しとVMの状態の検査のために、いくつかのメソッドを提供します。DTraceプローブは、これらの各メソッドのエントリ・ポイントとリターン・ポイントで提供されます。プローブは、hotspot_jniプロバイダによって提供されます。プローブの名前は、JNIメソッドの名前に、入るプローブの場合は-entry、戻るプローブの場合は-returnを付けたものとなります。それぞれの入るプローブで使用可能な引数は、その機能に提供された引数です。この場合、Invoke*メソッドは例外で、Javaメソッドに渡される引数を省略します。戻るプローブには、引数としてメソッドの戻り値があります(利用可能な場合)。

サンプルDTraceプローブ

provider hotspot {
probe vm-init-begin();
probe vm-init-end();
probe vm-shutdown();
probe class-loaded(
char* class_name, uintptr_t class_name_len, uintptr_t class_loader_id, bool is_shared);
probe class-unloaded(
char* class_name, uintptr_t class_name_len, uintptr_t class_loader_id, bool is_shared);
probe gc-begin(bool is_full);
probe gc-end();
probe mem-pool-gc-begin(
char* mgr_name, uintptr_t mgr_name_len, char* pool_name, uintptr_t pool_name_len,
uintptr_t initial_size, uintptr_t used, uintptr_t committed, uintptr_t max_size);
probe mem-pool-gc-end(
char* mgr_name, uintptr_t mgr_name_len, char* pool_name, uintptr_t pool_name_len,
uintptr_t initial_size, uintptr_t used, uintptr_t committed, uintptr_t max_size);
probe thread-start(
char* thread_name, uintptr_t thread_name_length,
uintptr_t java_thread_id, uintptr_t native_thread_id, bool is_daemon);
probe thread-stop(
char* thread_name, uintptr_t thread_name_length,
uintptr_t java_thread_id, uintptr_t native_thread_id, bool is_daemon);
probe method-compile-begin(
char* class_name, uintptr_t class_name_len,
char* method_name, uintptr_t method_name_len,
char* signature, uintptr_t signature_len);
probe method-compile-end(
char* class_name, uintptr_t class_name_len,
char* method_name, uintptr_t method_name_len,
char* signature, uintptr_t signature_len,
bool is_success);
probe compiled-method-load(
char* class_name, uintptr_t class_name_len,
char* method_name, uintptr_t method_name_len,
char* signature, uintptr_t signature_len,
void* code, uintptr_t code_size);
probe compiled-method-unload(
char* class_name, uintptr_t class_name_len,
char* method_name, uintptr_t method_name_len,
char* signature, uintptr_t signature_len);
probe monitor-contended-enter(
uintptr_t java_thread_id, uintptr_t monitor_id,
char* class_name, uintptr_t class_name_len);
probe monitor-contended-entered(
uintptr_t java_thread_id, uintptr_t monitor_id,
char* class_name, uintptr_t class_name_len);
probe monitor-contended-exit(
uintptr_t java_thread_id, uintptr_t monitor_id,
char* class_name, uintptr_t class_name_len);
probe monitor-wait(
uintptr_t java_thread_id, uintptr_t monitor_id,
char* class_name, uintptr_t class_name_len,
uintptr_t timeout);
probe monitor-waited(
uintptr_t java_thread_id, uintptr_t monitor_id,
char* class_name, uintptr_t class_name_len);
probe monitor-notify(
uintptr_t java_thread_id, uintptr_t monitor_id,
char* class_name, uintptr_t class_name_len);
probe monitor-notifyAll(
uintptr_t java_thread_id, uintptr_t monitor_id,
char* class_name, uintptr_t class_name_len);
probe method-entry(
uintptr_t java_thread_id, char* class_name, uintptr_t class_name_len,
char* method_name, uintptr_t method_name_len,
char* signature, uintptr_t signature_len);
probe method-return(
uintptr_t java_thread_id, char* class_name, uintptr_t class_name_len,
char* method_name, uintptr_t method_name_len,
char* signature, uintptr_t signature_len);
probe object-alloc(
uintptr_t java_thread_id, char* class_name, uintptr_t class_name_len,
uintptr_t size);
};

provider hotspot_jni {
probe AllocObject-entry(void*, void*);
probe AllocObject-return(void*);
probe AttachCurrentThreadAsDaemon-entry(void*, void**, void*);
probe AttachCurrentThreadAsDaemon-return(uint32_t);
probe AttachCurrentThread-entry(void*, void**, void*);
probe AttachCurrentThread-return(uint32_t);
probe CallBooleanMethodA-entry(void*, void*, uintptr_t);
probe CallBooleanMethodA-return(uintptr_t);
probe CallBooleanMethod-entry(void*, void*, uintptr_t);
probe CallBooleanMethod-return(uintptr_t);
probe CallBooleanMethodV-entry(void*, void*, uintptr_t);
probe CallBooleanMethodV-return(uintptr_t);
probe CallByteMethodA-entry(void*, void*, uintptr_t);
probe CallByteMethodA-return(char);
probe CallByteMethod-entry(void*, void*, uintptr_t);
probe CallByteMethod-return(char);
probe CallByteMethodV-entry(void*, void*, uintptr_t);

probe CallByteMethodV-return(char);
probe CallCharMethodA-entry(void*, void*, uintptr_t);
probe CallCharMethodA-return(uint16_t);
probe CallCharMethod-entry(void*, void*, uintptr_t);
probe CallCharMethod-return(uint16_t);
probe CallCharMethodV-entry(void*, void*, uintptr_t);
probe CallCharMethodV-return(uint16_t);
probe CallDoubleMethodA-entry(void*, void*, uintptr_t);
probe CallDoubleMethodA-return(double);
probe CallDoubleMethod-entry(void*, void*, uintptr_t);
probe CallDoubleMethod-return(double);
probe CallDoubleMethodV-entry(void*, void*, uintptr_t);
probe CallDoubleMethodV-return(double);
probe CallFloatMethodA-entry(void*, void*, uintptr_t);
probe CallFloatMethodA-return(float);
probe CallFloatMethod-entry(void*, void*, uintptr_t);
probe CallFloatMethod-return(float);
probe CallFloatMethodV-entry(void*, void*, uintptr_t);
probe CallFloatMethodV-return(float);
probe CallIntMethodA-entry(void*, void*, uintptr_t);
probe CallIntMethodA-return(uint32_t);
probe CallIntMethod-entry(void*, void*, uintptr_t);
probe CallIntMethod-return(uint32_t);
probe CallIntMethodV-entry(void*, void*, uintptr_t);
probe CallIntMethodV-return(uint32_t);
probe CallLongMethodA-entry(void*, void*, uintptr_t);
probe CallLongMethodA-return(uintptr_t);
probe CallLongMethod-entry(void*, void*, uintptr_t);
probe CallLongMethod-return(uintptr_t);
probe CallLongMethodV-entry(void*, void*, uintptr_t);
probe CallLongMethodV-return(uintptr_t);
probe CallNonvirtualBooleanMethodA-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualBooleanMethodA-return(uintptr_t);
probe CallNonvirtualBooleanMethod-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualBooleanMethod-return(uintptr_t);
probe CallNonvirtualBooleanMethodV-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualBooleanMethodV-return(uintptr_t);
probe CallNonvirtualByteMethodA-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualByteMethodA-return(char);
probe CallNonvirtualByteMethod-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualByteMethod-return(char);
probe CallNonvirtualByteMethodV-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualByteMethodV-return(char);
probe CallNonvirtualCharMethodA-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualCharMethodA-return(uint16_t);
probe CallNonvirtualCharMethod-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualCharMethod-return(uint16_t);
probe CallNonvirtualCharMethodV-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualCharMethodV-return(uint16_t);
probe CallNonvirtualDoubleMethodA-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualDoubleMethodA-return(double);
probe CallNonvirtualDoubleMethod-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualDoubleMethod-return(double);
probe CallNonvirtualDoubleMethodV-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualDoubleMethodV-return(double);
probe CallNonvirtualFloatMethodA-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualFloatMethodA-return(float);
probe CallNonvirtualFloatMethod-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualFloatMethod-return(float);
probe CallNonvirtualFloatMethodV-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualFloatMethodV-return(float);
probe CallNonvirtualIntMethodA-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualIntMethodA-return(uint32_t);
probe CallNonvirtualIntMethod-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualIntMethod-return(uint3t);
probe CallNonvirtualIntMethodV-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualIntMethodV-return(uint32_t);
probe CallNonvirtualLongMethodA-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualLongMethodA-return(uintptr_t);
probe CallNonvirtualLongMethod-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualLongMethod-return(uintptr_t);
probe CallNonvirtualLongMethodV-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualLongMethodV-return(uintptr_t);
probe CallNonvirtualObjectMethodA-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualObjectMethodA-return(void*);
probe CallNonvirtualObjectMethod-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualObjectMethod-return(void*);
probe CallNonvirtualObjectMethodV-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualObjectMethodV-return(void*);
probe CallNonvirtualShortMethodA-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualShortMethodA-return(uint16_t);
probe CallNonvirtualShortMethod-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualShortMethod-return(uint16_t);
probe CallNonvirtualShortMethodV-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualShortMethodV-return(uint16_t);
probe CallNonvirtualVoidMethodA-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualVoidMethodA-return();
probe CallNonvirtualVoidMethod-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualVoidMethod-return();
probe CallNonvirtualVoidMethodV-entry(void*, void*, void*, uintptr_t);
probe CallNonvirtualVoidMethodV-return();
probe CallObjectMethodA-entry(void*, void*, uintptr_t);
probe CallObjectMethodA-return(void*);
probe CallObjectMethod-entry(void*, void*, uintptr_t);
probe CallObjectMethod-return(void*);
probe CallObjectMethodV-entry(void*, void*, uintptr_t);
probe CallObjectMethodV-return(void*);
probe CallShortMethodA-entry(void*, void*, uintptr_t);
probe CallShortMethodA-return(uint16_t);
probe CallShortMethod-entry(void*, void*, uintptr_t);
probe CallShortMethod-return(uint16_t);
probe CallShortMethodV-entry(void*, void*, uintptr_t);
probe CallShortMethodV-return(uint16_t);
probe CallStaticBooleanMethodA-entry(void*, void*, uintptr_t);
probe CallStaticBooleanMethodA-return(uintptr_t);
probe CallStaticBooleanMethod-entry(void*, void*, uintptr_t);
probe CallStaticBooleanMethod-return(uintptr_t);
probe CallStaticBooleanMethodV-entry(void*, void*, uintptr_t);
probe CallStaticBooleanMethodV-return(uintptr_t);
probe CallStaticByteMethodA-entry(void*, void*, uintptr_t);
probe CallStaticByteMethodA-return(char);
probe CallStaticByteMethod-entry(void*, void*, uintptr_t);
probe CallStaticByteMethod-return(char);
probe CallStaticByteMethodV-entry(void*, void*, uintptr_t);
probe CallStaticByteMethodV-return(char);
probe CallStaticCharMethodA-entry(void*, void*, uintptr_t);
probe CallStaticCharMethodA-return(uint16_t);
probe CallStaticCharMethod-entry(void*, void*, uintptr_t);
probe CallStaticCharMethod-return(uint16_t);
probe CallStaticCharMethodV-entry(void*, void*, uintptr_t);
probe CallStaticCharMethodV-return(uint16_t);
probe CallStaticDoubleMethodA-entry(void*, void*, uintptr_t);
probe CallStaticDoubleMethodA-return(double);
probe CallStaticDoubleMethod-entry(void*, void*, uintptr_t);
probe CallStaticDoubleMethod-return(double);
probe CallStaticDoubleMethodV-entry(void*, void*, uintptr_t);
probe CallStaticDoubleMethodV-return(double);
probe CallStaticFloatMethodA-entry(void*, void*, uintptr_t);
probe CallStaticFloatMethodA-return(float);
probe CallStaticFloatMethod-entry(void*, void*, uintptr_t);
probe CallStaticFloatMethod-return(float);
probe CallStaticFloatMethodV-entry(void*, void*, uintptr_t);
probe CallStaticFloatMethodV-return(float);
probe CallStaticIntMethodA-entry(void*, void*, uintptr_t);
probe CallStaticIntMethodA-return(uint32_t);
probe CallStaticIntMethod-entry(void*, void*, uintptr_t);
probe CallStaticIntMethod-return(uint32_t);
probe CallStaticIntMethodentry(void*, void*, uintptr_t);
probe CallStaticIntMethodV-return(uint32_t);
probe CallStaticLongMethodA-entry(void*, void*, uintptr_t);
probe CallStaticLongMethodA-return(uintptr_t);
probe CallStaticLongMethod-entry(void*, void*, uintptr_t);
probe CallStaticLongMethod-return(uintptr_t);
probe CallStaticLongMethodV-entry(void*, void*, uintptr_t);
probe CallStaticLongMethodV-return(uintptr_t);
probe CallStaticObjectMethodA-entry(void*, void*, uintptr_t);
probe CallStaticObjectMethodA-return(void*);
probe CallStaticObjectMethod-entry(void*, void*, uintptr_t);
probe CallStaticObjectMethod-return(void*);
probe CallStaticObjectMethodV-entry(void*, void*, uintptr_t);
probe CallStaticObjectMethodV-return(void*);
probe CallStaticShortMethodA-entry(void*, void*, uintptr_t);
probe CallStaticShortMethodA-return(uint16_t);
probe CallStaticShortMethod-entry(void*, void*, uintptr_t);
probe CallStaticShortMethod-return(uint16_t);
probe CallStaticShortMethodV-entry(void*, void*, uintptr_t);
probe CallStaticShortMethodV-return(uint16_t);
probe CallStaticVoidMethodA-entry(void*, void*, uintptr_t);
probe CallStaticVoidMethodA-return();
probe CallStaticVoidMethod-entry(void*, void*, uintptr_t);
probe CallStaticVoidMethod-return();
probe CallStaticVoidMethodV-entry(void*, void*, uintptr_t);
probe CallStaticVoidMethodV-return();
probe CallVoidMethodA-entry(void*, void*, uintptr_t);
probe CallVoidMethodA-return();
probe CallVoidMethod-entry(void*, void*, uintptr_t);
probe CallVoidMethod-return();
probe CallVoidMethodV-entry(void*, void*, uintptr_t);
probe CallVoidMethodV-return();
probe CreateJavaVM-entry(void**, void**, void*);
probe CreateJavaVM-return(uint32_t);
probe DefineClass-entry(void*, const char*, void*, char, uintptr_t);
probe DefineClass-return(void*);
probe DeleteGlobalRef-entry(void*, void*);
probe DeleteGlobalRef-return();
probe DeleteLocalRef-entry(void*, void*);
probe DeleteLocalRef-return();
probe DeleteWeakGlobalRef-entry(void*, void*);
probe DeleteWeakGlobalRef-return();
probe DestroyJavaVM-entry(void*);
probe DestroyJavaVM-return(uint32_t);
probe DetachCurrentThread-entry(void*);
probe DetachCurrentThread-return(uint32_t);
probe EnsureLocalCapacity-entry(void*, uint32_t);
probe EnsureLocalCapacity-return(uint32_t);
probe ExceptionCheck-entry(void*);
probe ExceptionCheck-return(uintptr_t);
probe ExceptionClear-entry(void*);
probe ExceptionClear-return();
probe ExceptionDescribe-entry(void*);
probe ExceptionDescribe-return();
probe ExceptionOccurred-entry(void*);
probe ExceptionOccurred-return(void*);
probe FatalError-entry(void* env, const char*);
probe FindClass-entry(void*, const char*);
probe FindClass-return(void*);
probe FromReflectedField-entry(void*, void*);
probe FromReflectedField-return(uintptr_t);
probe FromReflectedMethod-entry(void*, void*);
probe FromReflectedMethod-return(uintptr_t);
probe GetArrayLength-entry(void*, void*);
probe GetArrayLength-return(uintptr_t);
probe GetBooleanArrayElements-entry(void*, void*, uintptr_t*);
probe GetBooleanArrayElements-return(uintptr_t*);
probe GetBooleanArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, uintptr_t*);
probe GetBooleanArrayRegion-return();
probe GetBooleanField-entry(void*, void*, uintptr_t);
probe GetBooleanField-return(uintptr_t);
probe GetByteArrayElements-entry(void*, void*, uintptr_t*);
probe GetByteArrayElements-return(char*);
probe GetByteArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, char*);
probe GetByteArrayRegion-return();
probe GetByteField-entry(void*, void*, uintptr_t);
probe GetByteField-return(char);
probe GetCharArrayElements-entry(void*, void*, uintptr_t*);
probe GetCharArrayElements-return(uint16_t*);
probe GetCharArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, uint16_t*);
probe GetCharArrayRegion-return();
probe GetCharField-entry(void*, void*, uintptr_t);
probe GetCharField-return(uint16_t);
probe GetCreatedJavaVMs-eintptr_t*);
probe GetCreatedJavaVMs-return(uintptr_t);
probe GetCreateJavaVMs-entry(void*, uintptr_t, uintptr_t*);
probe GetCreateJavaVMs-return(uint32_t);
probe GetDefaultJavaVMInitArgs-entry(void*);
probe GetDefaultJavaVMInitArgs-return(uint32_t);
probe GetDirectBufferAddress-entry(void*, void*);
probe GetDirectBufferAddress-return(void*);
probe GetDirectBufferCapacity-entry(void*, void*);
probe GetDirectBufferCapacity-return(uintptr_t);
probe GetDoubleArrayElements-entry(void*, void*, uintptr_t*);
probe GetDoubleArrayElements-return(double*);
probe GetDoubleArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, double*);
probe GetDoubleArrayRegion-return();
probe GetDoubleField-entry(void*, void*, uintptr_t);
probe GetDoubleField-return(double);
probe GetEnv-entry(void*, void*, void*);
probe GetEnv-return(uint32_t);
probe GetFieldID-entry(void*, void*, const char*, const char*);
probe GetFieldID-return(uintptr_t);
probe GetFloatArrayElements-entry(void*, void*, uintptr_t*);
probe GetFloatArrayElements-return(float*);
probe GetFloatArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, float*);
probe GetFloatArrayRegion-return();
probe GetFloatField-entry(void*, void*, uintptr_t);
probe GetFloatField-return(float);
probe GetIntArrayElements-entry(void*, void*, uintptr_t*);
probe GetIntArrayElements-return(uint32_t*);
probe GetIntArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, uint32_t*);
probe GetIntArrayRegion-return();
probe GetIntField-entry(void*, void*, uintptr_t);
probe GetIntField-return(uint32_t);
probe GetJavaVM-entry(void*, void**);
probe GetJavaVM-return(uint32_t);
probe GetLongArrayElements-entry(void*, void*, uintptr_t*);
probe GetLongArrayElements-return(uintptr_t*);
probe GetLongArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, uintptr_t*);
probe GetLongArrayRegion-return();
probe GetLongField-entry(void*, void*, uintptr_t);
probe GetLongField-return(uintptr_t);
probe GetMethodID-entry(void*, void*, const char*, const char*);
probe GetMethodID-return(uintptr_t);
probe GetObjectArrayElement-entry(void*, void*, uintptr_t);
probe GetObjectArrayElement-return(void*);
probe GetObjectClass-entry(void*, void*);
probe GetObjectClass-return(void*);
probe GetObjectField-entry(void*, void*, uintptr_t);
probe GetObjectField-return(void*);
probe GetObjectRefType-entry(void*, void*);
probe GetObjectRefType-return(void*);
probe GetPrimitiveArrayCritical-entry(void*, void*, uintptr_t*);
probe GetPrimitiveArrayCritical-return(void*);
probe GetShortArrayElements-entry(void*, void*, uintptr_t*);
probe GetShortArrayElements-return(uint16_t*);
probe GetShortArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, uint16_t*);
probe GetShortArrayRegion-return();
probe GetShortField-entry(void*, void*, uintptr_t);
probe GetShortField-return(uint16_t);
probe GetStaticBooleanField-entry(void*, void*, uintptr_t);
probe GetStaticBooleanField-return(uintptr_t);
probe GetStaticByteField-entry(void*, void*, uintptr_t);
probe GetStaticByteField-return(char);
probe GetStaticCharField-entry(void*, void*, uintptr_t);
probe GetStaticCharField-return(uint16_t);
probe GetStaticDoubleField-entry(void*, void*, uintptr_t);
probe GetStaticDoubleField-return(double);
probe GetStaticFieldID-entry(void*, void*, const char*, const char*);
probe GetStaticFieldID-return(uintptr_t);
probe GetStaticFloatField-entry(void*, void*, uintptr_t);
probe GetStaticFloatField-return(float);
probe GetStaticIntField-entry(void*, void*, uintptr_t);
probe GetStaticIntField-return(uint32_t);
probe GetStaticLongField-entry(void*, void*, uintptr_t);
probe GetStaticLongField-return(uintptr_t);
probe GetStaticMethodID-entry(void*, void*, const char*, const char*);
probe GetStaticMethodID-return(uintptr_t);
probe GetStaticObjectField-entry(void*, void*, uintptr_t);
probe GetStaticObjectField-return(void*);
probe GetStaticShortField-entry(void*, void*, uintptr_t);
probe GetStaticShortField-return(uint16_t);
pro GetStringChars-entry(void*, void*, uintptr_t*);
probe GetStringChars-return(const uint16_t*);
probe GetStringCritical-entry(void*, void*, uintptr_t*);
probe GetStringCritical-return(const uint16_t*);
probe GetStringLength-entry(void*, void*);
probe GetStringLength-return(uintptr_t);
probe GetStringRegion-entry(void*, void*, uintptr_t, uintptr_t, uint16_t*);
probe GetStringRegion-return();
probe GetStringUTFChars-entry(void*, void*, uintptr_t*);
probe GetStringUTFChars-return(const char*);
probe GetStringUTFLength-entry(void*, void*);
probe GetStringUTFLength-return(uintptr_t);
probe GetStringUTFRegion-entry(void*, void*, uintptr_t, uintptr_t, char*);
probe GetStringUTFRegion-return();
probe GetSuperclass-entry(void*, void*);
probe GetSuperclass-return(void*);
probe GetVersion-entry(void*);
probe GetVersion-return(uint32_t);
probe IsAssignableFrom-entry(void*, void*, void*);
probe IsAssignableFrom-return(uintptr_t);
probe IsInstanceOf-entry(void*, void*, void*);
probe IsInstanceOf-return(uintptr_t);
probe IsSameObject-entry(void*, void*, void*);
probe IsSameObject-return(uintptr_t);
probe MonitorEnter-entry(void*, void*);
probe MonitorEnter-return(uint32_t);
probe MonitorExit-entry(void*, void*);
probe MonitorExit-return(uint32_t);
probe NewBooleanArray-entry(void*, uintptr_t);
probe NewBooleanArray-return(void*);
probe NewByteArray-entry(void*, uintptr_t);
probe NewByteArray-return(void*);
probe NewCharArray-entry(void*, uintptr_t);
probe NewCharArray-return(void*);
probe NewDirectByteBuffer-entry(void*, void*, uintptr_t);
probe NewDirectByteBuffer-return(void*);
probe NewDoubleArray-entry(void*, uintptr_t);
probe NewDoubleArray-return(void*);
probe NewFloatArray-entry(void*, uintptr_t);
probe NewFloatArray-return(void*);
probe NewGlobalRef-entry(void*, void*);
probe NewGlobalRef-return(void*);
probe NewIntArray-entry(void*, uintptr_t);
probe NewIntArray-return(void*);
probe NewLocalRef-entry(void*, void*);
probe NewLocalRef-return(void*);
probe NewLongArray-entry(void*, uintptr_t);
probe NewLongArray-return(void*);
probe NewObjectA-entry(void*, void*, uintptr_t);
probe NewObjectA-return(void*);
probe NewObjectArray-entry(void*, uintptr_t, void*, void*);
probe NewObjectArray-return(void*);
probe NewObject-entry(void*, void*, uintptr_t);
probe NewObject-return(void*);
probe NewObjectV-entry(void*, void*, uintptr_t);
probe NewObjectV-return(void*);
probe NewShortArray-entry(void*, uintptr_t);
probe NewShortArray-return(void*);
probe NewString-entry(void*, const uint16_t*, uintptr_t);
probe NewString-return(void*);
probe NewStringUTF-entry(void*, const char*);
probe NewStringUTF-return(void*);
probe NewWeakGlobalRef-entry(void*, void*);
probe NewWeakGlobalRef-return(void*);
probe PopLocalFrame-entry(void*, void*);
probe PopLocalFrame-return(void*);
probe PushLocalFrame-entry(void*, uint32_t);
probe PushLocalFrame-return(uint32_t);
probe RegisterNatives-entry(void*, void*, const void*, uint32_t);
probe RegisterNatives-return(uint32_t);
probe ReleaseBooleanArrayElements-entry(void*, void*, uintptr_t*, uint32_t);
probe ReleaseBooleanArrayElements-return();
probe ReleaseByteArrayElements-entry(void*, void*, char*, uint32_t);
probe ReleaseByteArrayElements-return();
probe ReleaseCharArrayElements-entry(void*, void*, uint16_t*, uint32_t);
probe ReleaseCharArrayElements-return();
probe ReleaseDoubleArrayElements-entry(void*, void*, double*, uint32_t);
probe ReleaseDoubleArrayElements-return();
probe ReleaseFloatArrayElements-entry(void*, void*, float*, uint32_t);
probe ReleaseFloatArrayElements-return();
probe ReleaseIntArrayElements-entry(void*, void*, uint32_t*, uint32_t);
probe ReleaseIntArrayElements-return();
probe ReleaseLongArrayElements-entry(void*, void*, uintptr_t*, uint32_t);
probe ReleaseLongArrayElements-return();
probe ReleaseObjectArrayElements-entry(void*, void*, void**, uint32_t);
probe ReleaseObjectArrayElements-return();
probe Releasey(void*, void*, void*, uint32_t);
probe ReleasePrimitiveArrayCritical-return();
probe ReleaseShortArrayElements-entry(void*, void*, uint16_t*, uint32_t);
probe ReleaseShortArrayElements-return();
probe ReleaseStringChars-entry(void*, void*, const uint16_t*);
probe ReleaseStringChars-return();
probe ReleaseStringCritical-entry(void*, void*, const uint16_t*);
probe ReleaseStringCritical-return();
probe ReleaseStringUTFChars-entry(void*, void*, const char*);
probe ReleaseStringUTFChars-return();
probe SetBooleanArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, const uintptr_t*);
probe SetBooleanArrayRegion-return();
probe SetBooleanField-entry(void*, void*, uintptr_t, uintptr_t);
probe SetBooleanField-return();
probe SetByteArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, const char*);
probe SetByteArrayRegion-return();
probe SetByteField-entry(void*, void*, uintptr_t, char);
probe SetByteField-return();
probe SetCharArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, const uint16_t*);
probe SetCharArrayRegion-return();
probe SetCharField-entry(void*, void*, uintptr_t, uint16_t);
probe SetCharField-return();
probe SetDoubleArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, const double*);
probe SetDoubleArrayRegion-return();
probe SetDoubleField-entry(void*, void*, uintptr_t, double);
probe SetDoubleField-return();
probe SetFloatArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, const float*);
probe SetFloatArrayRegion-return();
probe SetFloatField-entry(void*, void*, uintptr_t, float);
probe SetFloatField-return();
probe SetIntArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, const uint32_t*);
probe SetIntArrayRegion-return();
probe SetIntField-entry(void*, void*, uintptr_t, uint32_t);
probe SetIntField-return();
probe SetLongArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, const uintptr_t*);
probe SetLongArrayRegion-return();
probe SetLongField-entry(void*, void*, uintptr_t, uintptr_t);
probe SetLongField-return();
probe SetObjectArrayElement-entry(void*, void*, uintptr_t, void*);
probe SetObjectArrayElement-return();
probe SetObjectField-entry(void*, void*, uintptr_t, void*);
probe SetObjectField-return();
probe SetShortArrayRegion-entry(void*, void*, uintptr_t, uintptr_t, const uint16_t*);
probe SetShortArrayRegion-return();
probe SetShortField-entry(void*, void*, uintptr_t, uint16_t);
probe SetShortField-return();
probe SetStaticBooleanField-entry(void*, void*, uintptr_t, uintptr_t);
probe SetStaticBooleanField-return();
probe SetStaticByteField-entry(void*, void*, uintptr_t, char);
probe SetStaticByteField-return();
probe SetStaticCharField-entry(void*, void*, uintptr_t, uint16_t);
probe SetStaticCharField-return();
probe SetStaticDoubleField-entry(void*, void*, uintptr_t, double);
probe SetStaticDoubleField-return();
probe SetStaticFloatField-entry(void*, void*, uintptr_t, float);
probe SetStaticFloatField-return();
probe SetStaticIntField-entry(void*, void*, uintptr_t, uint32_t);
probe SetStaticIntField-return();
probe SetStaticLongField-entry(void*, void*, uintptr_t, uintptr_t);
probe SetStaticLongField-return();
probe SetStaticObjectField-entry(void*, void*, uintptr_t, void*);
probe SetStaticObjectField-return();
probe SetStaticShortField-entry(void*, void*, uintptr_t, uint16_t);
probe SetStaticShortField-return();
probe Throw-entry(void*, void*);
probe ThrowNew-entry(void*, void*, const char*);
probe ThrowNew-return(uint32_t);
probe Throw-return(uint32_t);
probe ToReflectedField-entry(void*, void*, uintptr_t, uintptr_t);
probe ToReflectedField-return(void*);
probe ToReflectedMethod-entry(void*, void*, uintptr_t, uintptr_t);
probe ToReflectedMethod-return(void*);
probe UnregisterNatives-entry(void*, void*);
probe UnregisterNatives-return(uint32_t);
};

10 致命的エラー・レポート

致命的なエラーとは、ネイティブ・メモリーの枯渇、メモリー・アクセス・エラー、またはプロセスに向けられた明示的なシグナルなどのエラーのことです。致命的なエラーは、アプリケーション内のネイティブ・コード(たとえば、開発者によって記述されたJava Native Interface (JNI)コードなど)、アプリケーションやJVMで使用するサードパーティのネイティブ・ライブラリ、またはJVM内のネイティブ・コードによってトリガーされます。致命的なエラーが原因でJava仮想マシン(JVM)をホストしているプロセスが終了すると、JVMはエラーに関する情報を収集し、クラッシュ・レポートを書込みます。

JVMは、エラーの性質と場所を特定しようと試みます。可能な場合、クラッシュ時のJVMとプロセスの状態に関する詳細な情報を書込みます。入手できる詳細は、プラットフォームおよびクラッシュの性質によって異なります。このエラー・レポート・メカニズムよって提供される情報を使用すると、アプリケーションのデバッグやサードパーティ・コードの問題の特定をより簡単に、効率よく行うことができます。エラー・メッセージからJVMコードの問題がわかれば、より正確で有用なバグ・レポートを提出できます。場合によっては、クラッシュ・レポートの生成によって、詳細なレポート生成を阻害する二次的なエラーが発生することがあります。

エラー・レポートの例

次の例は、アプリケーションのネイティブJNIコードのクラッシュに関するエラー・レポート(hs_err_pid18240.logファイル)の冒頭を示しています。

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f0f159f857d, pid=18240, tid=18245
#
# JRE version: Java(TM) SE Runtime Environment (9.0+167) (build 9-ea+167)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (9-ea+167, mixed mode, tiered, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# C  [libMyApp.so+0x57d]  Java_MyApp_readData+0x11
#
# Core dump will be written. Default location: /cores/core.18240)
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

---------------  S U M M A R Y ------------

Command Line: MyApp

Host: Intel(R) Xeon(R) CPU           X5675  @ 3.07GHz, 24 cores, 141G, Ubuntu 12.04 LTS
Time: Fri Apr 28 02:57:13 2017 EDT elapsed time: 2 seconds (0d 0h 0m 2s)

---------------  T H R E A D  ---------------

Current thread (0x00007f102c013000):  JavaThread "main" [_thread_in_native, id=18245, stack(0x00007f10345c0000,0x00007f10346c0000)]

Stack: [0x00007f10345c0000,0x00007f10346c0000],  sp=0x00007f10346be930,  free space=1018k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [libMyApp.so+0x57d]  Java_MyApp_readData+0x11
j  MyApp.readData()I+0
j  MyApp.main([Ljava/lang/String;)V+15
v  ~StubRoutines::call_stub
V  [libjvm.so+0x839eea]  JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x47a
V  [libjvm.so+0x896fcf]  jni_invoke_static(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, Thread*) [clone .isra.90]+0x21f
V  [libjvm.so+0x8a7f1e]  jni_CallStaticVoidMethod+0x14e
C  [libjli.so+0x4142]  JavaMain+0x812
C  [libpthread.so.0+0x7e9a]  start_thread+0xda

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  MyApp.readData()I+0
j  MyApp.main([Ljava/lang/String;)V+15
v  ~StubRoutines::call_stub

siginfo: si_signo: 11 (SIGSEGV), si_code: 1 (SEGV_MAPERR), si_addr: 0x0000000000000000

11 Java仮想マシン関連のリソース

次の関連リンクはJVMに関するものです。

- java.lang.invokeパッケージのドキュメント

- Da Vinci Machine Project

ツール

Java HotSpot VMのオペレーティング特性の一部は、コマンドライン・フラグを使用して制御できます。Javaアプリケーション・ランチャの詳細は、Java Platform, Standard Editionツール・リファレンスのJVMをモニターするためのコマンドを参照してください。

Oracleの法律上の注意点

コピーライト

Copyright © 1994-2018, Oracle and/or its affiliates. All rights reserved.

ライセンス制約の保証と結果的に生じる損害の免責

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

保証免責

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクルまでご連絡ください。

制限付権利について

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs. No other rights are granted to the U.S. Government.

危険な用途への使用について

このソフトウェアまたはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアまたはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、Oracle Corporationおよびその関連会社は一切の責任を負いかねます。

商標と登録商標について

OracleおよびJavaはオラクルおよびその関連会社の登録商標です。その他の社名、商品名等は各社の商標または登録商標である場合があります。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

第三者のコンテンツ、製品、サービスに対する免責事項

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。適用されるお客様とOracle Corporationとの間の契約に別段の定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。適用されるお客様とOracle Corporationとの間の契約に定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

Pre-General Availability (一般提供前)版のドキュメントについて

このドキュメントがPre-General Availability (一般提供前)版の場合:

このドキュメントはPre-General Availability (一般提供前)版であり、デモおよび暫定使用のみを目的としたものです。このソフトウェアを使用するハードウェアに限定するものではありません。Oracle Corporationおよびその関連会社は、このドキュメントに関して一切の責任を負わず、いかなる保証もいたしません。また、このドキュメントを使用したことによって損失、費用、あるいは損害が発生しても、一切の責任を負いかねます。

非公開のPre-General Availability (一般提供前)版のドキュメントについて

このドキュメントが非公開のPre-General Availability (一般提供前)版の場合:

このドキュメントに含まれる情報は、情報の共有のみを目的としたものであって、顧客諮問委員会(Customer Advisory Board)のメンバーとしてのお客様の立場でのみ、またはお客様のPre-General Availability Trial Agreement (Pre-GAトライアル契約)のみに従って検討されるべきものとします。マテリアル、コード、または機能の提供をお約束するものではなく、購入決定を行う際の判断材料とすべきではありません。このドキュメントに記載されている特徴または機能の開発、リリースおよび時期については、オラクルの裁量により決定されます。

このドキュメントには、ソフトウェアまたは印刷物などの形式を問わず、オラクルが独占的な権利を有する財産的情報が含まれています。この機密資料へのアクセスと使用は、お客様とオラクルとの間で締結され、お客様が遵守に同意した、Oracle Master Agreement、Oracle License and Oracle Services Agreement (オラクル・ライセンスおよびサービスに関する契約書)、Oracle Partner Network Agreement、Oracle Distribution Agreementまたはその他のライセンス契約の条件に従うものとします。このドキュメントとその内容の開示、コピー、複製および配布には、オラクルによる事前の承諾を必要とします。このドキュメントはライセンス契約の一部となるものではなく、オラクルおよびその子会社や関連会社との契約を構成するものではありません。

ドキュメントのアクセシビリティ

オラクルのアクセシビリティについての詳細情報は、Oracle Accessibility ProgramのWebサイト(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc)を参照してください。

Oracle Supportへのアクセス

サポートをご契約のお客様には、My Oracle Supportを通して電子支援サービスを提供しています。詳細情報は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info)か、聴覚に障害のあるお客様は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs)を参照してください。