10 Javaアプリケーション・プロジェクトのテストとプロファイリング

JDeveloperでは、Javaコードの品質およびパフォーマンスを分析するためのツールが提供されています。これらのツールを使用して、コードの品質およびプログラミング・スキルを高めることができます。

この章の内容は次のとおりです。

Javaアプリケーション・プロジェクトのテストとプロファイリングについて

プロファイラは、実行中のプログラムに関する統計を収集して、パフォーマンスの問題を診断し、コードの非効率な箇所を修正します。

IDEには、ユニット・テストを作成および実行するためのツールやJavaアプリケーションをプロファイリングするためのツールが備わっています。ユニット・テストを使用すると、Javaアプリケーションのコードをテストできます。プロファイリングは、メモリーやパフォーマンスに関連する問題を特定するためにアプリケーションを調査するプロセスです。

Javaアプリケーションをプロファイリングするときには、Java仮想マシン(JVM)をモニターして、メソッドのタイミング、オブジェクトの割当ておよびガベージ・コレクションなどのアプリケーション・パフォーマンスに関するデータを取得できます。このデータを使用して、コードの中で、パフォーマンスを改善するために最適化できる可能性のある領域を特定できます。

次のプロファイリング機能を使用できます。

ユニット・テストによるJavaアプリケーション・プロジェクトのテスト

JUnitは、Java対応のリグレッション・テスト用オープン・ソース・フレームワークです。JUnitを使用して、Javaコードを検証するテストを記述および実行します。

テスト・フィクスチャ、テスト・ケースおよびテスト・スイートを作成するには、JDeveloperのJUnitウィザードを使用します。一般的なプロジェクト用のテスト・コンポーネントを作成するウィザードに加えて、ビジネス・コンポーネント・プロジェクトの専用ウィザードが提供されています。

Javaプロジェクトに対するJUnitテストの作成

JUnitテスト・アプリケーションは、1つ以上のテスト・ケース、テスト・フィクスチャ、ケースを起動するテスト・スイートおよびスイートを起動するランナーで構成されます。

JUnitテスト・アプリケーションは、次のコンポーネントで構成されます。

  • 1つ以上のテスト・ケース。テスト対象のメソッドを呼び出し、予測される結果についてのアサーションを作成します。デフォルトで生成されるテスト・ケース・クラスは「Test」という名前ですが、ユーザーが任意の有効なJava名を指定できます。

  • テスト・フィクスチャ。テストが実行される状態を提供します。任意のクラスをテスト・フィクスチャとして使用できますが、JDeveloperには専用のテスト・フィクスチャ・クラスを作成するウィザードも用意されています。デフォルトで生成されるテスト・フィクスチャ・クラスは「Fixture」という名前ですが、ユーザーが任意の有効なJava名を指定できます。

  • テスト・スイート。テスト・ケースを呼び出します。デフォルトのテスト・スイート・クラスは、「AllTests」という名前です。

  • ランナー。テスト・スイートを呼び出し、テスト結果を相関付けて表示します。

JUnitカスタム・テスト・フィクスチャの作成方法

テスト・フィクスチャは、既知の値を持つオブジェクトのセットで構成され、テスト・ケースにデータを提供します。JUnitのカスタムのテスト・フィクスチャ・クラスを作成する手順を使用してください。

テスト・フィクスチャとは、既知の値を持つオブジェクトのセットで、テスト・ケースにデータを提供します。任意のクラスをテスト・フィクスチャとして使用できますが、JDeveloperにはカスタムのテスト・フィクスチャ・クラスや様々な専用のテスト・フィクスチャ・クラスを作成できるウィザードも用意されています。

ノート:

UnitTestFixtureはpublicクラスです。そのインスタンスを作成した場合、生成されたコードにエラーは生じません。

AppModuleAMFixtureはprivateクラスです。そのインスタンスを作成した場合、生成されたコードにはエラーが生じます。

JUnitのカスタムのテスト・フィクスチャ・クラスを作成するには:

  1. 「アプリケーション」ウィンドウで、プロジェクトを選択します。
  2. 「ファイル」「新規」「ギャラリから」を選択します。
  3. 「カテゴリ」ツリーで「一般」を開き、「ユニット・テスト」を選択します。
  4. 「項目」リストで、「テスト・フィクスチャ」をダブルクリックします。
  5. ウィザードを完了するとテスト・フィクスチャ・クラスが作成されます。

    ウィザードによって作成されたクラスが、編集用に開かれます。

  6. 必要に応じてファイルを変更します。

    特に、テスト・フィクスチャ・オブジェクトを初期化するコードをsetUp()メソッドに追加します。取得したリソースをすべてリリースするコードをtearDown()メソッドに追加します。

JunitのJDBCテスト・フィクスチャの作成方法

テスト・フィクスチャはテスト・ケース用のデータを提供し、JDBCテスト・フィクスチャはテスト・ケース用のデータベース接続を作成します。JUnitのJDBCテスト・フィクスチャ・クラスを作成する手順を使用してください。

テスト・フィクスチャとは、既知の値を持つオブジェクトのセットで、テスト・ケースにデータを提供します。JDBCテスト・フィクスチャは、使用するテスト・ケースにデータベース接続を確立するコードを提供します。

JUnitのJDBCテスト・フィクスチャ・クラスを作成するには:

  1. 「アプリケーション」ウィンドウで、プロジェクトを選択します。

  2. 「ファイル」「新規」「ギャラリから」を選択します。

  3. 「カテゴリ」ツリーで「一般」を開き、「ユニット・テスト」(JUnit)を選択します。

  4. 「項目」リストで、「テスト・フィクスチャ」をダブルクリックします。

  5. ダイアログを完了するとテスト・フィクスチャ・クラスが作成されます。

    作成されたクラスが、編集用に開かれます。

  6. 必要に応じてファイルを変更します。具体的には、テスト・フィクスチャ・オブジェクトを初期化するコードをsetUp()メソッドに追加し、取得されたリソースを解放するコードをtearDown()メソッドに追加します。

JUnitテスト・ケースの作成

テスト・ケース・クラスは、JUnitのアサーションを呼び出し、そのメソッドを使用してテストを実行します。JUnitのテスト・ケース・クラスを作成する手順を使用してください。

テスト・ケース・クラスには、JUnitのアサーションを呼び出してテストを実行する1つ以上のメソッドがあります。次の例は、JUnit 3.xでの典型的なテスト・ケースを示します。この例では、テスト対象のメソッドにテスト・フィクスチャ・データを渡してから、その結果を既知の値と比較し、予測どおりかどうかを確認しています。

public void testCountChars()
{
      int expected = 4;
      int actual = fixture1.countChars('a');
      assertEquals(expected, actual);
}
@Test
public void testCountChars()
{
      int expected = 4;
      int actual = fixture1.countChars('a');
      Assert.assertEquals(expected, actual);
}

前述のテスト・ケースでは、countChars()がテスト対象であり、テストの結果をassertEquals()でチェックしています。これは、JUnit Assertクラスで定義されているアサーション・メソッドの一種です。テスト・フィクスチャfixture1の状態はsetUp()メソッドで確立され、このメソッドは次に示すようにテスト・ケースの呼出しより前に呼び出されています。

protected void setup() throws Exception
{
fixture1 = new StringFixture("Goin' to Kansas City, Kansas City, here I come.");
}

JUnitテスト・ケース・クラスを作成するには:

  1. 「アプリケーション」ウィンドウで、プロジェクト、またはテストする必要のある特定のクラスを選択します。
  2. 「ファイル」「新規」「ギャラリから」を選択します。
  3. 「カテゴリ」ツリーで「一般」を開き、「ユニット・テスト」を選択します。
  4. 「項目」リストで、「テスト・ケース」をダブルクリックします。
  5. 「テスト・ケースの作成」ダイアログの「テストするクラスの選択」ページで、「テスト中のクラス」に入力するか、「参照」をクリックします。
  6. 「クラス・ブラウザ」ダイアログで、テストするクラスを確認します。または、「クラス名を一致」フィールドに最初の文字を入力します。「一致するクラス」リストは識別しやすいようにフィルタ処理されます。

    クラスを選択し、「OK」をクリックして、ダイアログを閉じます。「次へ」をクリックします。

  7. テストする個別のメソッドを選択し、「次へ」をクリックします。
  8. 「テスト・ケース・クラスの設定」ダイアログで、テスト・ケース、パッケージ、その拡張対象のクラスの名前を入力し、JUnitでスタブが作成される組込み機能のリストを選択します。「次へ」をクリックします。
  9. 「テスト・フィクスチャの選択」ページで、テスト・ケースに追加するテスト・フィクスチャを選択するか、「参照」をクリックします。
  10. テスト・ケースに追加するテスト・フィクスチャがすべてリスト中で選択されていることを確認し、「終了」をクリックします。

    ウィザードによって作成されたクラスが、編集用に開かれます。

EJBアプリケーション専用のテスト・ケースを作成できます。詳細は、「JUnitを使用したEJBユニットのテスト方法」を参照してください。

JUnitテスト・ケースにテストを追加する方法

メソッドに対するユニット・テストを、JUnitテスト・ケース・クラスに追加できます。JUnitテスト・ケース・クラスにテストを追加する手順を使用してください。

メソッドに対するユニット・テストを、既存のJUnitテスト・ケース・クラスに追加できます。

JUnitテスト・ケース・クラスにテストを追加するには:

  1. コード・エディタで、新しいユニット・テストを作成するメソッドを選択します。
  2. メイン・メニューから「ソース」「新規メソッドのテスト」を選択します。
  3. 「既存のTestCaseクラスに追加」を選択します。
  4. 「クラス名」ドロップダウン・ボックスから、または「参照」を使用して、新しいテストを追加するテスト・ケース・クラスを選択します。
  5. 新しいテストをテスト・ケースに追加するには、「OK」をクリックします。

JUnitテスト・スイートの作成

main()メソッドおよびTestRunnerクラスに対する呼出しを挿入すると、「JUnit TestRunner」ログ・ウィンドウでテスト結果を表示できます。JUnitテスト・スイート・クラスを作成する手順を使用してください。

テスト・スイートは、テスト・ケースを呼び出すクラスです。

「JUnitテスト・スイート」ウィザードには、main()メソッドと、TestRunnerクラスへのコールを挿入するオプションがあります。このオプションによってJDeveloperで「JUnit TestRunner」ログ・ウィンドウが開き、テスト結果が表示されます。別のテスト・ランナーを使用する場合には、メソッドを編集します。

次に示したJUnit 3.xテスト・スイートでは、suite()メソッドによってTestSuiteインスタンスが作成され、それにテスト・ケースが追加されます。テスト・ケースを追加または削除する場合には、このメソッドを編集します。

public class AllTests {
    public static Test suite() {
    TestSuite suite;
    suite = new TestSuite("project1.AllTests");
    return suite;    }        

次に示したJUnit 4テスト・スイートでは、テスト・ケース・クラスは@Suiteおよび@RunWithの注釈を付けて記述されています。

@RunWith(Suite.class)
@Suite.SuiteClasses( {})
public class AllTests1 {
    public static void main(String[] args) {
    String[] args2 = { AllTests1.class.getName() };
    org.junit.runner.JUnitCore.main(args2);
    }
}

JUnitテスト・スイート・クラスを作成するには:

JUnitテスト・ケースを作成する前に、テストされるプロジェクトの作成を完了している必要があります。

  1. 「アプリケーション」ウィンドウで、プロジェクトを選択します。
  2. 「ファイル」「新規」「ギャラリから」を選択します。
  3. 「カテゴリ」ツリーで「一般」を開き、「ユニット・テスト」(JUnit)を選択します。
  4. 「項目」リストで、「テスト・スイート」をダブルクリックします。
  5. ウィザードを完了するとテスト・スイート・クラスが作成されます。ウィザードによって作成されたクラスが、編集用に表示されます。
  6. 必要に応じてファイルを変更します。具体的には、次のとおりです。
    • suite()メソッドでテスト・ケースを追加します。

    • main()メソッドで、必要に応じてランナーの呼出しを置き換えます。

ビジネス・コンポーネント・テスト・スイートの作成方法

JUnit BC4Jテスト・スイート・ウィザードを使用して、アプリケーション・モジュール内のすべてのビュー・オブジェクトに対し、テストを生成します。ビジネス・コンポーネント・テスト・スイートを作成する手順を使用してください。

作成されるテキスト・フィクスチャは、接続数を減らすシングルトン・クラスです。テスト・ケースごとに接続または切断する場合は、JUnit 4の注釈、@Beforeおよび@Afterを使用してテスト・ケースをカスタマイズします。

JUnit BC4Jテスト・スイート・ウィザードでは、アプリケーション・モジュールの各ビュー・オブジェクトに対してテストが生成されます。アプリケーション・モジュールがメソッドをエクスポートしていない場合、ウィザードによって、アプリケーション・モジュールそのもののテストも生成されます。生成されるビュー・オブジェクト・クラスの形式はview_objectVOTest.javaであり、形式がpackage.view.viewobjectVOのパッケージに収められます。この場合のpackageはアプリケーション・モジュール・パッケージです。生成されるアプリケーション・モジュール・テストの形式はapplication_moduleAMTest.javaであり、形式がpackage.applicationModuleのパッケージに配置されます。生成されるテスト・フィクスチャ・クラスの形式はapplicationmoduleAMFixture.javaであり、アプリケーション・モジュール・テストと同じパッケージに配置されます。

生成されるすべてのテスト・スイート・クラスの形式はAllapplicationmoduleTest.javaであり、アプリケーション・モジュールのパッケージ名と同じ名前でパッケージに配置されます。

各アプリケーション・モジュールまたはビュー・オブジェクト・テストについてテスト・ケースのXMLファイルも生成されます。このXMLファイルには、アプリケーション・モジュールまたはビュー・オブジェクト・テスト・ケースで定義されているテスト・メソッドが含まれます。重複が多くなりすぎる可能性があるため、ベース・クラス(ある場合)のテスト・メソッドは含まれません。

ビジネス・コンポーネント・テスト・スイートを作成するには:

  1. メイン・メニューから、「ファイル」を選択し、「新規」を選択します。

    ビジネス・コンポーネント・テスト用に別のプロジェクトを作成します。

  2. 「新規ギャラリ」で、「一般」を展開し、「プロジェクト」「Javaプロジェクト」の順に選択して、「OK」をクリックします。
  3. Javaプロジェクトの作成ウィザードの「プロジェクト名」ページで、テスト・プロジェクトの名前とディレクトリ・パスを入力し、「次へ」をクリックします。
  4. プロジェクトのJava設定ページで、パッケージ名、プロジェクトのJavaソース・コードのディレクトリ、および出力クラス・ファイルが配置される出力ディレクトリを入力し、「終了」をクリックします。
  5. 「アプリケーション」ウィンドウで、テストするアプリケーション・モジュールをダブルクリックします。
  6. 概要エディタで、「Java」ナビゲーション・タブをクリックします。
  7. 「Java」ページで、「Javaクラス」セクションの「編集」アイコンをクリックします。
  8. 「Javaオプションの選択」ダイアログで「アプリケーション・モジュール・クラスの生成」を選択して、「OK」をクリックします。
  9. 概要エディタの「Java」ページで、「クラス・インタフェース」セクションの「編集」アイコンをクリックします。
  10. 「クライアント・インタフェースの編集」ダイアログで、テストするメソッドを「選択済」ペインに移動して、「OK」をクリックします。
  11. 「アプリケーション」ウィンドウで、作成したテスト・プロジェクトを右クリックして、「新規」を選択します。
  12. 「新規ギャラリ」で、「一般」を展開し、「ユニット・テスト」「ビジネス・コンポーネントのテスト・スイート」の順に選択して、「OK」をクリックします。
  13. JUnit BC4Jテスト・スイート・ウィザードの「テストの構成」ページで次の値を選択し、「次へ」をクリックします。
    • ビジネス・コンポーネント・プロジェクト: テストするアプリケーション・モジュールを含むプロジェクトを選択します。

    • アプリケーション・モジュール: テストするアプリケーション・モジュールを選択します。

    • 構成: ローカル・アプリケーション・モジュールまたは共有アプリケーション・モジュールを選択します。

    • 「ベース・クラスのテスト」→「アプリケーション・モジュール拡張」: 様々なベース・クラスを指定できます。生成されるテスト・ケース・クラスはそのベース・クラスから拡張されます。このとき、ベース・クラスのすべてのpublic抽象メソッドの本体は単純なデフォルトの実装になります。

    • 「ベース・クラスのテスト」→「ビュー・オブジェクト拡張」: ビュー・オブジェクトが拡張するクラスを指定できます。生成されるテスト・ケース・クラスはそのベース・クラスから拡張されます。このとき、ベース・クラスのすべてのpublic抽象メソッドの本体は単純なデフォルトの実装になります。

  14. 「サマリー」ページで選択内容を確認して、「終了」をクリックします。

Business Componentsテスト・フィクスチャの作成方法

ビジネス・コンポーネント・テスト・フィクスチャは、個別に作成することも、ビジネス・コンポーネント・テスト・スイートとあわせて作成することもできます。ビジネス・コンポーネント・テスト・フィクスチャを作成する手順を使用してください。

ビジネス・コンポーネントのテスト・スイートを作成すると、ビジネス・コンポーネントのテスト・フィクスチャも一緒に作成されます。また、ビジネス・コンポーネントのテスト・フィクスチャを個別に作成することもできます。

生成されるテスト・フィクスチャ・クラスの形式はapplicationmoduleAMFixture.javaであり、形式がpackage.applicationModuleのパッケージに配置されます。この場合のpackageはアプリケーション・モジュール・パッケージです。

ビジネス・コンポーネント・テスト・フィクスチャを作成するには:

  1. メイン・メニューで、「ファイル」「新規」「ギャラリから」を選択します。

    ビジネス・コンポーネント・テスト用に別のプロジェクトを作成します。

  2. 「新規ギャラリ」で、「一般」を開き、「プロジェクト」「Javaプロジェクト」を選択して、「OK」をクリックします。
  3. Javaプロジェクトの作成ダイアログの「プロジェクト名」ページで、テスト・プロジェクトの名前とディレクトリ・パスを入力し、「次へ」をクリックします。
  4. プロジェクトのJava設定ページで、パッケージ名、ソース・ディレクトリおよび出力ディレクトリを入力し、「終了」をクリックします。
  5. 「アプリケーション」ウィンドウで、テストするアプリケーション・モジュールをダブルクリックします。
  6. 概要エディタで「Java」ナビゲーション・タブをクリックし、「Javaクラス」セクションの「編集」アイコンをクリックします。
  7. 「Javaオプションの選択」ダイアログで「アプリケーション・モジュール・クラスの生成」を選択して、「OK」をクリックします。
  8. 概要エディタの「Java」ページで、「クラス・インタフェース」セクションの「編集」アイコンをクリックします。
  9. 「クライアント・インタフェースの編集」ダイアログで、テストするメソッドを「選択済」ペインに移動して、「OK」をクリックします。
  10. 「アプリケーション」ウィンドウで、作成したテスト・プロジェクトを右クリックして、「新規」を選択します。
  11. 「新規ギャラリ」で、「一般」を展開し、「ユニット・テスト」「ビジネス・コンポーネントのテスト・フィクスチャ」の順に選択して、「OK」をクリックします。
  12. JUnit BC4Jテスト・フィクスチャ・ウィザードの「テストの構成」ページで次の値を選択し、「次へ」をクリックします。
    • ビジネス・コンポーネント・プロジェクト: テストするアプリケーション・モジュールを含むプロジェクトを選択します。

    • アプリケーション・モジュール: テストするアプリケーション・モジュールを選択します。

    • 構成: ローカル・アプリケーション・モジュールまたは共有アプリケーション・モジュールを選択します。

  13. 「サマリー」ページでテスト・フィクスチャ・クラスを確認して、「終了」をクリックします。

プロジェクトのすべてのテスト・ケースでテスト・スイートを更新する方法

プロジェクト内のすべてのテスト・ケースでテスト・スイートを更新します。テスト・スイートを更新する手順を使用してください。

プロジェクトのすべてのテスト・ケースでテスト・スイートを更新します。

テスト・スイートを更新するには:

  1. suite()メソッドを持つクラスで、コンテキスト・メニューから「ソース」「テスト・スイートのリフレッシュ」を選択します。
  2. テスト・ケースのリストにあるすべての項目がチェックされていることを確認してください。
  3. テスト・スイートを更新するには「OK」をクリックします。

JUnitテスト・スイートの実行方法

正常にコンパイルされたテスト・スイートを実行できます。JUnitテスト・スイートを実行する手順を使用してください。

テスト・スイートが正常にコンパイルされたら、実行できます。

JUnitテスト・スイートを実行するには:

  1. 「アプリケーション」ウィンドウで、テスト・スイート・クラスを選択します。
  2. 右クリックして「実行」を選択します。

    テストが実行され、テスト・ランナーによって結果が表示されます。

プロファイリング・セッションの開始

プロファイラを起動する様々な方法を学習します。

JDeveloperでは、プロファイラを起動するために、次の経路を提供します。

JDeveloperアプリケーションを同時に起動およびプロファイリング

JDeveloperアプリケーションおよびそのアプリケーションのプロファイリングを開始する手順を使用してください。

次のステップで、JDeveloperアプリケーションを起動するのと同時にそのアプリケーションをプロファイルできます。

  1. 「実行」「プロジェクトをプロファイル」を選択します
  2. メイン・ウィンドウで「セッションの構成」ボタンをクリックし、プロファイラ・モードをクリックして選択します。「プロファイル」ドロップダウン矢印をクリックして、任意の時点でプロファイラ・モードを変更できます。
  3. メイン・ウィンドウで「プロファイル」ボタンをクリックします。

    アプリケーションとプロファイル・セッションが同時に起動されます。

プロファイラの調整方法

アプリケーションのプロファイルにIDEを使用するには、その前に、プロファイリングに使用する各JDKについて調整プロセスが完了している必要があります。ローカル・システムでIDEを調整する手順を使用してください。

IDEを使用してアプリケーションのプロファイリングを実行するには、事前にIDEを調整しておく必要があります。この調整プロセスは、プロファイリングに使用するJDKごとに実行する必要があります。これは、アプリケーションのバイトコード計測によってある程度のオーバーヘッドが生じ、より正確な結果を得るためには、コード計測にかかる時間を要因から取り除く必要があるために行います。

IDEの調整は、使用するJDKごとに1回だけで十分です。ただし、システムのパフォーマンスに影響するような変更をローカル構成またはリモート構成に加えた場合には、調整プロセスを再実行することをお薦めします。システム・パフォーマンスに影響を与える可能性のある変更とは、次のようなものです。

  • ハードウェアのアップグレード

  • オペレーティング・システムの有意な変更またはアップグレード

  • プロファイリングに使用するJavaプラットフォームのアップグレード

ローカル・システム用にIDEを調整するには:

  1. 実行中のその他のプログラムをすべて終了します。

    IDEでは、他のアプリケーションを実行中であっても調整は実行されますが、調整の実行時にCPU集中型プログラムを実行すると、正確なプロファイリング結果が得られない可能性があります。

  2. 「ツール」「プリファレンス」「プロファイラ」「調整データの管理」に進み、「管理」ボタンをクリックします。

    「調整データの管理」ウィンドウが表示されます。

  3. プロファイリングに使用するJavaプラットフォームを選択します。「調整」をクリックします。

    「Javaプラットフォーム」をクリックして「ライブラリの管理」ウィンドウを開き、新規Javaプラットフォームを追加できます。「調整データの管理」ダイアログ・ボックスに、最近実行された調整の日付が表示されます。

「調整」をクリックすると、IDEでは選択したJavaプラットフォームで調整データが収集されます。調整プロセスが完了したら、IDEを使用してアプリケーションのプロファイリングを開始できます。

複数のコンピュータまたはシステム間で調整データを共有しないようにしてください。

実行中のJDeveloperアプリケーションへのプロファイラのアタッチ

すでに実行しているJDeveloperプロジェクトをプロファイルする手順を使用してください。

次のステップを実行すると、すでに実行しているJDeveloperプロジェクトをプロファイルできます。

  1. 「実行」「プロジェクトにアタッチ」を選択します
  2. メイン・ウィンドウで「セッションの構成」ボタンをクリックし、プロファイラ・モードをクリックして選択します。「プロファイル」ドロップダウン矢印をクリックして、任意の時点でプロファイラ・モードを変更できます。

    ターゲット・アプリケーションがJDeveloper以外で実行されている場合、「プロジェクトへの設定のアタッチ」ターゲットを選択し、「アタッチ設定」ウィンドウで該当する選択を行います。

  3. メイン・ウィンドウで「アタッチ」ボタンをクリックします。

    実行中のアプリケーションを追跡するプロファイル・セッションが起動されます。

外部アプリケーションのプロファイリング

JDeveloper IDE以外で起動されたアプリケーションをプロファイルする手順を使用してください。

次のステップを実行すると、JDeveloper IDE以外で起動されたアプリケーションをプロファイルできます。

  1. 「実行」「外部プロセスにアタッチ」を選択します

    メイン・ウィンドウに「外部プロセスのプロファイル」タブが表示されます。

  2. 「セッションの構成」ボタンをクリックし、「プロセスへの設定のアタッチ」を選択します

    「アタッチ設定」ウィンドウが表示されます。

  3. 「プロファイル」ドロップダウン・メニューでプロファイルするアプリケーションのタイプを選択し、プロファイルするプロセスを選択します。「アタッチ設定」ウィンドウでは、各オプションの詳細な手順を説明し表示します。「OK」をクリックします。
  4. メイン・ウィンドウで「セッションの構成」ボタンをクリックし、プロファイラ・モードをクリックして選択します。「プロファイル」ドロップダウン矢印をクリックして、任意の時点でプロファイラ・モードを変更できます。
  5. 「アタッチ」ボタンをクリックします。

    選択済のアプリケーションを追跡するプロファイル・セッションが起動されます。

プロファイリング・データのスナップショットの取得およびアクセス

プロファイリング・セッションの実行中またはプロファイル・セッションの終了時にスナップショットを取得して、特定の時点でのプロファイリング・データを取得し、「スナップショット」ウィンドウを使用してそのデータを表示します。

スナップショットでは、特定の時点のプロファイリング・データが取り込まれ、「スナップショット」ウィンドウを通じてアクセスできます。「スナップショットのアクセス」を参照してください

スナップショットは、次の点でプロファイリングのライブ結果とは異なります。

  • スナップショットは、プロファイリング・セッションが実行中でなくても確認できます。

  • スナップショットは容易に比較できます。

スナップショットを取得するためのオプションは次の2つです。

プロファイリング・セッションの最後でのスナップショットの取得

プロファイリング・セッションの終了時には「アプリケーション終了」ダイアログが表示され、このダイアログを使用して、収集された結果のスナップショットを取得できます。

プロファイリング・セッションの進行中に、プロファイルされたアプリケーションを閉じる場合、またはそれ自体が閉じる場合、プロファイラは「アプリケーション終了」ダイアログを表示することにより、その時点までに収集された結果のスナップショットを取得するかを尋ねます。

図10-1 「アプリケーション終了」ダイアログ

図10-1の説明が続きます
「図10-1 「アプリケーション終了」ダイアログ」の説明

「はい」をクリックしてスナップショットを保存します。

プロファイリング・セッション中のスナップショットの取得

「スナップショット」オプションを使用して、プロファイリング・セッション中の任意の時点におけるプロファイリング・データのスナップショットを取得します。

次の図で示す「スナップショット」アイコンをクリックすることで、プロファイリング・データのスナップショットはプロファイリング・セッションのどの時点ででも取得できます。

図10-2 「スナップショット」アイコン

図10-2の説明が続きます
「図10-2 「スナップショット」アイコン」の説明

セッション中にスナップショット機能がどのように動作するかを制御するには、「ツール」「プリファレンス」「プロファイラ」の順に進み、「スナップショットの取得時」ドロップダウン・メニューをクリックして次のオプションを表示します。

新規スナップショットを開く—「スナップショット」アイコンをクリックした直後にスナップショットが開きます

新規スナップショットを保存—「スナップショット」アイコンをクリックするたびに新規スナップショットが保存されます

新規スナップショットを開いて保存—「スナップショット」アイコンをクリックした直後にスナップショットが保存されて開きます。

プロファイリング・セッション中に複数のスナップショットを取得することもでき、セッションの終わりにfinalスナップショットを保存するよう求められます。

「アプリケーション終了」ダイアログの起動および停止

「ツール」の「設定」メニューに示される「プロファイラ」オプションを使用して、閉じられている「アプリケーション終了」ダイアログをリセットします。

「アプリケーション終了」ダイアログがプロファイリング・セッションの終わりに表示される際に、「今後このメッセージを表示しない」チェック・ボックスを選択すると、ダイアログは今後表示されなくなります。後でこのダイアログの表示を再度有効にする場合は、「ツール」「プリファレンス」「プロファイラ」に進み、次の図に示すように「リセット」ボタンをクリックします。

図10-3 「プロファイラ」の「プリファレンス」ダイアログの「リセット」ボタン

図10-3の説明が続きます
「図10-3 「プロファイラ」の「プリファレンス」ダイアログの「リセット」ボタン」の説明

スナップショットのアクセス

「ウィンドウ」の「プロファイリング」メニューの「スナップショット」オプションを使用してアクセスする「スナップショット」ウィンドウには、プロファイリング・セッションに対して取得されたスナップショットが表示されます。

「ウィンドウ」「プロファイリング」「スナップショット」の順に進むことで、プロファイリング・セッション・スナップショットにアクセスできます。次の図で示すように、「スナップショット」ウィンドウが表示されます。

図10-4 「スナップショット」ウィンドウ

図10-4の説明が続きます
「図10-4 「スナップショット」ウィンドウ」の説明

「スナップショット」ウィンドウの最下部には、選択したスナップショットをエクスポート、オープン、名前変更および削除するアイコンがあります。

ヒープ・ダンプの取得

プロファイル・セッションの実行中にヒープ・ダンプを取得し、プロジェクトまたはローカル・ファイル・システムにヒープを保存して、ダンプをロードし、ヒープ・ダンプ内のオブジェクトを実行中のプロファイル・セッション外で参照できるようにします。プロファイリング・ポイントを使用してヒープ・ダンプを取得する手順を使用してください。

プロファイリング・セッションの進行中にヒープ・ダンプを取得できます。ヒープ・ダンプを取得するときに、ヒープをプロジェクトまたはローカル・ファイル・システムに保存するよう要求されます。ヒープ・ダンプを保存した後で、随時ヒープ・ダンプをロードして、ヒープ上のオブジェクトを参照したり、個別オブジェクトの参照を特定したり、ヒープ・ダンプの比較によるスナップショット間の相違を確認したりすることができます。ヒープ・ダンプをロードしたり参照したりするために、プロファイリング・セッションが実行中である必要はありません。

ヒープ・ダンプを取得するには、アプリケーションがJDK 1.5.0_12またはそれ以降で実行している必要があります。

プロファイリング・ポイントを使用してヒープ・ダンプを取得するには:

  1. プロファイリング・ポイントを配置するコードが含まれているソース・ファイルを開きます。

  2. プロファイリング・ポイントを配置するコードの行を右クリックして、「プロファイリング・ポイントの追加」を選択します。

  3. 「プロファイリング・ポイント・タイプ」リストで、次のスナップショット・ポイントのいずれか1つを選択して「次へ」をクリックします。

    • スナップショットの取得

    • 時間によるスナップショットの取得

    • トリガーによるスナップショットの取得

  4. ウィザードの「プロパティのカスタマイズ」ページで、スナップショットのタイプとして「ヒープ・ダンプ」を選択し、追加設定を変更します。「ヒープ・ダンプ」オプションは、「設定」→「取得」から使用できます。

プロファイリング・ポイントを使用してヒープ・ダンプを取得する際、プロファイリング・ポイントを配置するソース・コード内のポイントを指定します。たとえば、スレッドが特定のメソッドに入ったときに、ヒープ・ダンプを取得する必要が生じることがあります。

OutOfMemoryエラー時にヒープ・ダンプを取得するには:

  1. メイン・メニューから、「ツール」「プリファレンス」「プロファイラ」を選択します。
  2. 「OutOfMemoryError時」リストで、OutOfMemoryError発生時のIDEの動作を指定するオプションをドロップダウン・リストから選択します。

    デフォルトの動作は、ヒープ・ダンプをプロファイル済プロジェクトに保存することです。

ヒープ・ウォーカ付きのUI要素の表示

ヒープ・ダンプ・ビューアのヒープ・ウォーカを使用して、アプリケーションUIの正確な場所を特定します。これには、文字列値やファイル・パスなどのオブジェクトの論理値が表示される他、UI属性および要素のビジュアル・スナップショットも提供されます。

ヒープ・ダンプ・ビューア(ヒープ・ウォーカ)は、String値、ファイル・パス、URLアドレスなどの論理値を表示します。さらに、UI属性のビジュアル・スナップショットおよび要素(色、フォント、ボタンなど)を提供します。

ヒープ・ダンプに表示されているほとんどのクラスおよびインスタンスでは、テキストのプロパティおよび数字のプロパティがデータ構造の説明と検査およびメモリー・リーク、非効率なメモリー使用などのバグの検出に適しています。ただし、多くの種類のオブジェクトにおいて、インメモリー表現はオブジェクトが何であるかを即座に決定する場合には適していません。

ビジュアル表示機能は、UI要素の検査に最適です。ここでは、オブジェクト・プロパティの表示は、アプリケーションUIの正確な場所を識別できるほど精密ではありません。たとえば、UIコンテナのネストされた要素に対する位置、サイズおよび参照を単に読み込むだけでは、オブジェクトがアプリケーションによって作成された「ファイルを開く」ダイアログを表すことにユーザーが気づかない可能性があります。

指定したクラスのインスタンスを参照して、ヒープ・ダンプ要素のイメージ表現にアクセスします。図10-5は、ヒープがダンプされた時点で、アプリケーション・ウィンドウのビジュアル・プレビューを含むヒープ・ウォーカ・パネルを表示します。

図10-5 ヒープ・ウォーカ - イメージ・プレビュー

図10-5の説明が続きます
「図10-5 ヒープ・ウォーカ - イメージ・プレビュー」の説明
イメージ・プレビュー・ユースケース

ヒープ・ウォーカのイメージ・プレビュー機能を使用すると、選択されているUI要素を特定し、ヒープのダンプ時のアプリケーションの状態を判別し、メモリー内でUIスニペットを検索し、重複を検出できる他、UIをオフラインで分析できます。

ヒープ・ウォーカ・イメージ・プレビューは次のユースケースで有用です。

  • 選択したUI要素の識別。特定のUI要素(ボタン、ラベルなど)を検索する必要がある場合に、希望する種類のインスタンスを参照します

  • ヒープをダンプする時点でのアプリケーションの状態の判断。ユーザーによって報告されるバグは、必要なすべての情報が含まれていなかったり、重要な詳細情報が欠けていたりすることがよくあります。アプリケーションUIを表示することで、ユーザーはメモリー不足の例外がスローされた際にテキスト・ドキュメントがロード中であるなどが即座にわかります。

  • 予定外にメモリーに残ってしまったUIスニペットの検索。UIのパーツはメモリーからリリースされていないことがあり、表、ツリーまたはエディタが大きなデータ・モデルを参照する場合に深刻な問題を引き起こす可能性があります。たとえば、「パネル」要素を参照することで、ユーザーはこれらのスニペットを簡単に検出でき、どれぐらいのメモリーが活用されていないかがわかり、UIのリリースを妨げている問題を識別できます。

  • 重複の検出。イメージを参照することで、リソースを無駄にしている、メモリーに割り当てられている同じイメージの複数のインスタンスなどをユーザーは即座に表示できます。

  • オフラインUI分析。ヒープ・ウォーカはヒープ・ダンプからUI構造を再作成できます。この方法で、UI開発者は別の互換性のないシステムで実行されている可能性のある実際のアプリケーションにアクセスすることなく、UI作成ブロックを分析できます

イメージのプレビュー機能に対する次のような例外を確認することが重要です。

  • ツリー・データの表示はサポートされていません。

  • フォアグラウンド、バックグラウンドまたはフォント属性は特定の実装では表示されない可能性があります。

  • カスタム・コントロールは表示できません。

  • 特定要素のUIテキストは「インスタンス」ビューではフルに表示されない可能性があります。

オブジェクト問合せ言語(OQL)を使用したヒープ・ダンプの分析方法

JavaScript式言語に基づくオブジェクト問合せ言語は、Javaヒープを問い合せてコンテンツをフィルタします。「ヒープ」ウィンドウでJavaヒープをロードするときに、このウィンドウの「OQLコンソール」タブをクリックして、OQLエディタを開きます。

OQLはSQLに似た問合せ言語であり、Javaヒープに問い合わせて、そのJavaヒープから要求された情報のフィルタ処理/選択を可能にします。「クラスXのすべてのインスタンスを表示」というような事前定義の問合せはツールによってすでにサポートされていますが、OQLでは柔軟性が高くなっています。OQLは、JavaScript式言語に基づいています。

「ヒープ」ウィンドウでJavaヒープをロードする際、このウィンドウの「OQLコンソール」タブをクリックしてOQLエディタを開くことができます。OQLコンソールには、OQLエディタ、保存済OQL問合せウィンドウ、および問合せ結果を表示するウィンドウが含まれています。任意のサンプルOQL問合せを使用したり、ヒープ・データをフィルタ処理および選択する問合せを作成して、Javaヒープから必要な情報を特定することができます。問合せを選択または作成した後で、Javaヒープに対して問合せを実行して、結果を表示できます。

OQL問合せのフォームは次のとおりです。

select <JavaScript expression to select>
[ from [instanceof] <class name> <identifier>
[ where <JavaScript boolean expression to filter> ] ]

ここでは、class nameは完全修飾Javaクラス名(例: java.net.URL)または配列クラス名、char[] (または[C)はchar配列名、java.io.File (または[Ljava.io.File;)はjava.io.File[]の名前、というようになります。完全修飾されたクラス名が、実行時にJavaクラスを常に一意に識別するとはかぎりません。同名であっても、別のローダーによってロードされた複数のJavaクラスが存在している場合もあります。したがって、クラス名にはクラス・オブジェクトのID文字列が使用できます。instanceofキーワードが使用されている場合は、サブタイプ・オブジェクトが選択されます。このキーワードが指定されていない場合は、指定されたクラスのインスタンスのみが選択されます。from句とwhere句は両方ともオプションです。

select句および(オプションとして)where句では、式はJavaScript式で使用されます。フィールドに自然構文でアクセスできるようにするために、Javaヒープ・オブジェクトは便利なスクリプト・オブジェクトとしてラップされます。たとえば、Javaフィールドはobj.field_name構文でアクセスでき、配列要素はarray[index]構文でアクセスできます。選択されたJavaオブジェクトはそれぞれ、from句で指定された識別子名のJavaScript変数にバインドされます。

OQLの例

例を参考にして、OQLを使用してヒープを問い合せます。

長さが100以上のStringをすべて選択します。

select s from java.lang.String s where s.count >= 100

長さが256以上のint配列をすべて選択します。

select a from int[] a where a.length >= 256

正規表現に一致するStringのコンテンツを表示します。

select {instance: s, content: s.toString()} from java.lang.String s
    where /java/(s.toString())

すべてのFileオブジェクトのパス値を表示します。

select file.path.toString() from java.io.File file

すべてのClassLoaderクラスの名前を表示します。

select classof(cl).name 
    from instanceof java.lang.ClassLoader cl

指定されたID文字列によって識別されるClassのインスタンスを表示します。

select o from instanceof 0xd404b198 o

0xd404b198はClassのIDです(セッション内)。これを検索するには、そのクラスのページに表示されたIDを調べます。

OQLの組込みオブジェクトと関数

次のリストに、ヒープでサポートされる組込みオブジェクトを示します。

ヒープ・オブジェクト

ヒープ組込みオブジェクトは、次のメソッドをサポートしています。

  • heap.forEachClass: Javaクラスごとにコールバック関数をコールします。

    heap.forEachClass(callback);
    
  • heap.forEachObject: Javaオブジェクトごとにコールバック関数をコールします。

    heap.forEachObject(callback, clazz, includeSubtypes);
    

    clazzは、インスタンスが選択されているクラスです。これが指定されない場合、java.lang.Object. includeSubtypesのデフォルトは、サブタイプ・インスタンスを含めるかどうかを指定するブール・フラグになります。このフラグのデフォルト値はtrueです。

  • heap.findClass: 指定された名前のJavaクラスを検索します。

    heap.findClass(className);
    

    この場合のclassNameは、検索するクラスの名前です。結果として得られるClassオブジェクトのプロパティは、次のとおりです。

    • name: クラスの名前。

    • superclass: スーパークラスのClassオブジェクト(または、java.lang.Objectの場合はnull)。

    • statics: Classの静的フィールドの名前と値のペア。

    • fields: フィールド・オブジェクトの配列。フィールド・オブジェクトのプロパティはnameとsignatureです。

    • loader: このクラスをロードしたClassLoaderオブジェクト。

    Classオブジェクトのメソッドは、次のとおりです。

    • isSubclassOf: 指定されたクラスがこのクラスの直接または間接サブクラスかどうかをテストします。

    • isSuperclassOf: 指定されたClassがこのクラスの直接または間接のスーパークラスかどうかをテストします。

    • subclasses: 直接および間接サブクラスの配列を返します。

    • superclasses: 直接および間接スーパークラスの配列を返します。

  • heap.findObject: 指定されたオブジェクトIDからオブジェクトを検索します。

    heap.findObject(stringIdOfObject);
    
  • heap.classes: すべてのJavaクラスの列挙を返します。

  • heap.objects: Javaオブジェクトの列挙を返します。

    heap.objects(clazz, [includeSubtypes], [filter])
    

    clazzは、インスタンスが選択されているクラスです。これが指定されない場合、java.lang.Object. includeSubtypesのデフォルトは、サブタイプ・インスタンスを含めるかどうかを指定するブール・フラグになります。このフラグのデフォルト値はtrueです。このメソッドでは、オプションのフィルタ式を受け入れてオブジェクトの結果セットをフィルタ処理します。

  • heap.finalizables: - ファイナライズが保留中であるJavaオブジェクトの列挙を返します。

  • heap.livepaths: - 指定されたオブジェクトがアライブしているパスの列挙を返します。このメソッドでは、ブール・フラグであるオプションの第2パラメータを受け入れます。このフラグにより、弱い参照のあるパスを含めるかどうかが指定されます。デフォルトでは、弱い参照のあるパスは含まれません。

    select heap.livepaths(s) from java.lang.String s
    

    この配列の各要素が、別の配列になっています。後の配列には、パスの「参照チェーン」に入っているオブジェクトが含まれています。

  • heap.roots: - ヒープのRootの列挙が返されます。

    各Rootオブジェクトのプロパティは、次のとおりです。

    • id: このルートにより参照されるオブジェクトの文字列ID

    • type: Rootの記述タイプ(JNIグローバル、JNIローカル、Java Staticなど)

    • description: Rootの文字列の記述

    • referrer: このルートに責任を持つ、またはnullであるThreadオブジェクトまたはClassオブジェクト

  • クラスjava.lang.Systemの静的フィールド'props'にアクセスします。

    select heap.findClass("java.lang.System").statics.props
    select heap.findClass("java.lang.System").props
    
  • java.lang.Stringクラスのフィールド数を取得します。

    select heap.findClass("java.lang.String").fields.length
    
  • オブジェクトIDが指定されているオブジェクトを検索します。

    select heap.findObject("0xf3800b58")
    
  • 名前パターンjava.net.*を持つクラスをすべて選択します。

    select filter(heap.classes(), "/java.net./(it.name)")
    

個別のオブジェクトに対する関数

  • allocTrace関数

    指定されたJavaオブジェクトがある場合は、その割当てサイト・トレースを返します。allocTraceはframeオブジェクトの配列を返します。各frameオブジェクトのプロパティは、次のとおりです。

    • className: メソッドがframeで実行中であるJavaクラスの名前。

    • methodName: - frameで実行中のJavaメソッドの名前。

    • methodSignature: frameで実行中のJavaメソッドのシグネチャ。

    • sourceFileName: frameで実行中のJavaクラスのソース・ファイルの名前。

    • lineNumber: メソッド内のソース行番号。

  • classof関数

    指定されたJavaオブジェクトのクラス・オブジェクトを返します。結果として得られるオブジェクトは次のプロパティをサポートしています。

    • name: クラスの名前。

    • superclass: スーパークラスのクラス・オブジェクト(または、java.lang.Objectの場合はnull)

    • statics: クラスの静的フィールドの名前と値のペア

    • fields: fieldオブジェクトの配列。fieldオブジェクトのプロパティはnameとsignatureです。

    • loader: このクラスをロードしたClassLoaderオブジェクト。

    Classオブジェクトのメソッドは、次のとおりです。

    • isSubclassOf: 指定されたクラスがこのクラスの直接または間接サブクラスかどうかをテストします。

    • isSuperclassOf: 指定されたクラスがこのクラスの直接または間接のスーパークラスかどうかをテストします。

    • subclasses: 直接および間接サブクラスの配列を返します。

    • superclasses: 直接および間接スーパークラスの配列を返します。

    • 各Referenceタイプ・オブジェクトのクラス名を表示します。

      select classof(o).name from instanceof java.lang.ref.Reference o
      
    • java.io.InputStreamのすべてのサブクラスを表示します。

      select heap.findClass("java.io.InputStream").subclasses()
      
    • java.io.BufferedInputStreamのすべてのスーパークラスを表示します。

      show all superclasses of java.io.BufferedInputStream 
      
  • forEachReferrer関数

    指定されたJavaオブジェクトのリファラごとにコールバック関数をコールします。

  • identical関数

    指定された2つのJavaオブジェクトが同一かどうかを返します。次に例を示します。

    select identical(heap.findClass("Foo").statics.bar, heap.findClass("AnotherClass").statics.bar)
    
  • objectid関数

    指定されたJavaオブジェクトの文字列IDを返します。このIDはheap.findObjectに渡すことができ、識別のためにオブジェクトを比較する場合にも使用できます。次に例を示します。

    select objectid(o) from java.lang.Object o
    
  • reachables関数

    指定されたJavaオブジェクトから推移的に参照されるJavaオブジェクトの配列を返します。オプションとして、カンマ区切りフィールド名である第2パラメータがアクセス可能性の計算から除外されることを受け入れます。フィールドはclass_name.field_nameパターンで作成されます。

    • 各Propertiesインスタンスからアクセス可能なオブジェクトをすべて印刷します。

      select reachables(p) from java.util.Properties p
      
    • java.net.URLからアクセス可能なオブジェクトをすべて印刷しますが、指定されたフィールド経由でアクセス可能なオブジェクトは省略されます。

      select reachables(u, 'java.net.URL.handler') from java.net.URL u
      
  • referrers関数

    指定されたJavaオブジェクトの参照を保持するJavaオブジェクトの列挙を返します。このメソッドでは、ブール・フラグであるオプションの第2パラメータを受け入れます。このフラグにより、弱い参照を含めるかどうかが指定されます。デフォルトでは、弱い参照は含まれません。

    • java.lang.Objectインスタンスごとにリファラ数を印刷します。

      select count(referrers(o)) from java.lang.Object o
      
    • java.io.Fileオブジェクトごとにリファラを印刷します。

      select referrers(f) from java.io.File f
      
    • 2つ以上で参照された場合のみ、URLオブジェクトを印刷します。

      select u from java.net.URL u where count(referrers(u)) > 2
      
  • referees関数

    指定されたJavaオブジェクトが直接参照するJavaオブジェクトの配列を返します。このメソッドでは、ブール・フラグであるオプションの第2パラメータを受け入れます。このフラグにより、弱い参照を含めるかどうかが指定されます。デフォルトでは、弱い参照は含まれません。たとえば、java.io.Fileクラスのすべての静的参照フィールドを印刷するには、次のようにします。

    select referees(heap.findClass("java.io.File"))
    
  • refers関数

    最初のJavaオブジェクトが2番目のJavaオブジェクトを参照するかどうかを返します。

  • root関数

    指定されたオブジェクトがオブジェクトのrootセットのメンバーである場合、この関数は、その理由を説明する説明Rootオブジェクトを返します。指定されたオブジェクトがrootではない場合、この関数はnullを返します。

  • sizeof関数

    指定されたJavaオブジェクトのサイズをバイト数で返します。次に例を示します。

    select sizeof(o) from int[] o
    
  • retainedsize関数

    指定されたJavaオブジェクトの保持セットのサイズをバイト数で返します。ノート: この関数をヒープ・ダンプに対してはじめて使用する場合は、かなり時間がかかる場合があります。

    retainedsize関数の使用例は次のとおりです。

    select rsizeof(o) from instanceof java.lang.HashMap o
    
  • toHtml関数

    指定されたJavaオブジェクトのHTML文字列を返します。これは、select式によって選択されたオブジェクトに対して自動的にコールされます。ただし、より複雑な出力の印刷に役立つ場合があります。たとえば、ハイパーリンクを太字で印刷するには、次のようにします。

    select "<b>" + toHtml(o) + "</b>" from java.lang.Object o
    
複数の値の選択

複数の値を選択するには、JavaScriptオブジェクトのリテラルまたは配列を使用します。

JavaScriptオブジェクトのリテラルまたは配列を使用して、複数の値を選択できます。

たとえば、スレッド・オブジェクトごとに名前とスレッドを表示します。

select { name: t.name? t.name.toString() : "null", thread: t } 
from instanceof java.lang.Thread t

配列/イテレータ/列挙操作関数

これらの関数は、配列/イテレータ/列挙および式文字列[または、コールバック関数]を入力として受け入れます。これらの関数は、配列/イテレータ/列挙を反復し、各要素に対して式(または関数)を適用します。ノート: JavaScriptオブジェクトは連想配列です。したがって、これらの関数は任意のJavaScriptオブジェクトとともに使用することもできます。

  • concat関数

    指定された配列/列挙に、指定されたブール式がコードで指定した要素が含まれているかどうかを返します。評価されたコードは、次の組込み変数を参照できます。

    • it: 現在参照している要素

    • index: 現在の要素の索引

    • array: 反復中の配列/列挙

    たとえば、一部の静的オブジェクトのいくつかのクラスによって参照されるPropertiesオブジェクトをすべて選択するには、次のようにします。

    select p from java.util.Properties p
    where contains(referrers(p), "classof(it).name == 'java.lang.Class'")
    
  • count関数

    指定されたブール式を満たす入力配列/列挙の要素の件数を返します。ブール式のコードは、次の組込み変数を参照できます。

    • it: 現在参照している要素

    • index: 現在の要素の索引

    • array: 反復中の配列/列挙

    たとえば、特定の名前パターンを持つクラスの数を印刷します。

    select count(heap.classes(), "/java.io./(it.name)")
    
  • filter関数

    指定されたブール式を満たす入力配列/列挙の要素が含まれている配列/列挙を返します。ブール式のコードは、次の組込み変数を参照できます。

    • it: 現在参照している要素

    • index: 現在の要素の索引

    • array: 反復中の配列/列挙

    • result: 結果の配列/列挙

    • java.io.*名前パターンを持つクラスをすべて表示します

      select filter(heap.classes(), "/java.io./(it.name)")
      
    • リファラがjava.netパッケージに属していないURLオブジェクトのすべてのリファラを表示します。

      select filter(referrers(u), "! /java.net./(classof(it).name)")
      from java.net.URL u
      
  • length関数

    配列/列挙の要素数を返します。

  • map関数

    指定されたコードを各要素で評価することにより、指定された配列/列挙を変換します。評価されたコードは、次の組込み変数を参照できます。

    • it: 現在参照している要素

    • index: 現在の要素の索引

    • array: 反復中の配列/列挙

    • result: 結果の配列/列挙

    Map関数は、入力配列/列挙の要素ごとにコードを繰り返しコールすることによって作成された値の配列/列挙を返します。

    たとえば、次の名前と値を持つjava.io.Fileの静的フィールドをすべて表示します。

    select map(heap.findClass("java.io.File").statics, "index + '=' + toHtml(it)")
    
  • max関数

    指定された配列/列挙の最大要素を返します。オプションとして、配列の要素を比較するコード式を受け入れます。デフォルトでは、数値比較が使用されます。比較式では、次の組込み変数が使用できます。

    • lhs: 比較の左辺の要素

    • rhs: 比較の右辺の要素

    • 最大長のstringインスタンスを検索します。

      select max(map(heap.objects('java.lang.String', false), 'it.count'))
      
    • 最大長であるstringインスタンスを検索します。

      select max(heap.objects('java.lang.String'), 'lhs.count > rhs.count')
      
  • min関数

    指定された配列/列挙の最小要素を返します。オプションとして、配列の要素を比較するコード式を受け入れます。デフォルトでは、数値比較が使用されます。比較式では、次の組込み変数が使用できます。

    • lhs: 比較の左辺の要素

    • rhs: 比較の右辺の要素

    • 最小サイズのvectorインスタンスを検索します。

      select min(map(heap.objects('java.util.Vector', false), 'it.elementData.length'))
    • 最大長であるvectorインスタンスを検索します。

      select min(heap.objects('java.util.Vector'), 'lhs.elementData.length < rhs.elementData.length')
      
  • sort関数

    指定された配列/列挙をソートします。オプションとして、配列の要素を比較するコード式を受け入れます。デフォルトでは、数値比較が使用されます。比較式では、次の組込み変数が使用できます。

    • lhs: 比較の左辺の要素

    • rhs: 比較の右辺の要素

    • すべてのchar[]オブジェクトをサイズ順に印刷します。

      select sort(heap.objects('char[]'), 'sizeof(lhs) - sizeof(rhs)')
      
    • すべてのchar[]オブジェクトをサイズ順に印刷しますが、サイズも併せて印刷します。

      select map(sort(heap.objects('char[]'), 'sizeof(lhs) - sizeof(rhs)'),  '{ size: sizeof(it), obj: it }')
      
  • top関数

    指定された配列/列挙の上位N個の要素を返します。オプションとして、配列の要素と上位要素の数を比較するコード式を受け入れます。デフォルトでは、外観の順序で上位10個の要素が返されます。比較式では、次の組込み変数が使用できます。

    • lhs: 比較の左辺の要素

    • rhs: 比較の右辺の要素

    • 5つの最長文字列を印刷します

      select top(heap.objects('java.lang.String'), 'rhs.count - lhs.count', 5)
      
    • 5つの最長文字列を印刷しますが、サイズも併せて印刷します。

      select map(top(heap.objects('java.lang.String'),  'rhs.count - lhs.count', 5), '{ length: it.count, obj: it }')
      
  • sum関数

    指定された入力配列または列挙のすべての要素の合計を返します。オプションとして、第2パラメータとして式を受け入れます。これは、入力要素を合計する前のマッピングに使用します。

    たとえば、各Propertiesオブジェクトからアクセス可能なサイズの合計を返します。

    select sum(map(reachables(p), 'sizeof(it)')) 
    from java.util.Properties p
     
    // or omit the map as in ...
    select sum(reachables(p), 'sizeof(it)') 
    from java.util.Properties p
    
  • toArray関数

    入力配列/列挙の要素が含まれている配列を返します。

  • unique関数

    指定された入力配列/列挙の一意の要素が含まれている配列/列挙を返します。

    次の例では、文字列から参照される一意のchar[]インスタンスを選択しています。複数の文字列インスタンスでコンテンツに対して同じchar[]を共有できます。

    // number of unique char[] instances referenced from any String
    select count(unique(map(heap.objects('java.lang.String'), 'it.value')))
     
    // total number of Strings
    select count(heap.objects('java.lang.String'))
    
その他の例

次の例に、各クラス・ローダーのヒストグラムとそれによってロードされたクラス数の印刷方法、および各クラス・ローダー・インスタンスの親子チェーンを示します。

次の例では、各クラス・ローダーのヒストグラムと、それによってロードされたクラス数が印刷されます。

java.lang.ClassLoaderには、タイプjava.util.Vectorのクラスであるprivateフィールドがあり、Vectorにはベクター内の要素数であるelementCountというprivateフィールドがあります。この問合せでは、JavaScriptオブジェクトのliteral関数およびmap関数を使用して複数の値(loader、count)を選択します。これは、sort関数を比較式とともに使用して、結果を件数(つまり、ロードされたクラス数)別にソートします。

select map(sort(map(heap.objects('java.lang.ClassLoader'), 
'{ loader: it, count: it.classes.elementCount }'), 'lhs.count < rhs.count'),
'toHtml(it) + "<br>"')

次の例では、クラス・ローダー・インスタンスごとに親子チェーンを示しています。

select map(heap.objects('java.lang.ClassLoader'),
      function (it) {
         var res = '';
         while (it != null) {
            res += toHtml(it) + "->";
            it = it.parent;
         }
         res += "null";
         return res + "<br>";
      })

java.lang.ClassLoaderクラスの親フィールドが使用されていて、コールをマップするためにコールバック関数を使用して親がnullになるまで検索していることに注意してください。

次の例では、すべてのSystemプロパティの値が印刷されます。この問合せ(および、その他の多くの問合せ)は、Javaプラットフォーム・クラスのprivateフィールドが通知(実装の詳細)なしに変更または削除された可能性があるため、安定していないことがあります。ただし、ユーザーのクラスを制御できる場合は、このような問合せをユーザーのクラスに使用しても安全です。

select map(filter(heap.findClass('java.lang.System').props.table, 'it != null && it.key != null && it.value != null'),
            function (it) {
                var res = it.key.toString() + ' = ' + it.value.toString();
                return res;
            });
  • java.lang.Systemには、タイプjava.util.Propertiesの'props'という名前の静的フィールドがあります。

  • java.util.Propertiesには、タイプjava.util.Hashtable$Entryの'table'というフィールドがあります(このフィールドはjava.util.Hashtableから継承されます)。これはハッシュ表バケット配列です。

  • java.util.Hashtable$Entryにはキー、値、およびnextフィールドがあります。各エントリは、同じハッシュ表バケット内で次のエントリ(またはnull)を指します。

  • java.lang.Stringクラスには、タイプchar[]のvalueフィールドがあります。

プロファイリング・ポイントの設定

特定のプロファイリング・アクションを起動するには、ソース・コード内にプロファイリング・ポイントを設定します。プロファイリング・ポイントを設定し、アクティブなプロファイリング・ポイントを表示する手順を使用してください。

プロファイリング・ポイントはソース・コード内のマーカーであり、特定のプロファイリング・アクションを起動できます。コードにプロファイリング・ポイントを設定するには、ソース・エディタのポップアップ・メニューを使用するか、「プロファイリング・ポイント」ウィンドウのツールバーを使用します。

次のタイプのプロファイリング・ポイントを設定できます。

  • 結果のリセット

  • ストップウォッチ

  • スナップショットの取得

  • 時間によるスナップショットの取得

  • トリガーによるスナップショットの取得

ノート: 「時間によるスナップショットの取得」および「トリガーによるスナップショットの取得」のアイコンは、コード・エディタには表示されません。これらのアイコンは「プロファイリング・ポイント」ウィンドウにのみ表示されます。

プロファイリング・ポイントを使用して、プロファイリング結果のリセット、スナップショットの取得、またはコード・フラグメントのタイムスタンプまたは実行時間の記録を行うことができます。

プロファイリング・ポイントは、一度設定されると、削除されるまでプロジェクトに含まれます。

プロファイリング・ポイントを設定するには:

  1. プロファイリング・ポイントを追加するクラスを特定して、ソース・エディタでそのクラスを開きます。

  2. ソース・エディタで、プロファイリング・ポイントを追加する行の左余白を右クリックします。

  3. 「プロファイリング・ポイントの追加」を選択して、「新規プロファイリング・ポイント」ウィザードを開きます。

  4. プロファイリング・ポイント・タイプとプロジェクトを選択します。

  5. 「次へ」をクリックします。

  6. 必要に応じて、プロファイリング・ポイントのプロパティをカスタマイズします。

  7. 「終了」をクリックします。

プロファイリング・ポイントのタイプを表すアイコンが、プロファイリング・ポイントを挿入したソース・エディタに表示されます。

プロファイリング・ポイントを有効または無効にするには、ソース・エディタで、プロファイリング・ポイントが含まれている行の左余白を右クリックして、<プロファイリング・ポイント名>「有効化」または「無効化」を選択します。

アクティブなプロファイリング・ポイントを表示するには:

  1. アプリケーションを開きます。
  2. メイン・メニューから、「実行」「プロファイル」を選択します。最後のプロファイル・モード・セッションが表示され、「プロファイリング・ポイント」セクションが表示されます。

    また、「ウィンドウ」「プロファイリング」「プロファイリング・ポイント」を選択することもできます。

  3. 「プロジェクト」列または「プロファイリング・ポイント」列を使用して定義されたプロファイリング・ポイントを表示します。

テレメトリのプロファイリング

テレメトリ・モードでは、「CPUとGC」、「メモリー」、「存続世代」および「スレッドとクラス」のメトリックが示されます。

テレメトリ・モードでは、次のメトリックを提供します。

CPUとGC—指定した時間に使用されるCPUおよびGCのパーセンテージを表示します

メモリー—ヒープ・サイズと指定した時間に使用されるヒープをMBで表示します

存続世代 —指定した時間の存続世代の数を表示します。また、GC間隔も表示します

スレッドとクラス—指定した時間にロードされるクラスおよびスレッドの数を表示します

プロファイリング・テレメトリ・セッションを起動するには、「プロファイラの起動について」を参照してください

図10-6に、テレメトリ・セッションのスナップショットを示します。

図10-6 テレメトリ・セッション

図10-6の説明が続きます
「図10-6 テレメトリ・セッション」の説明

メソッドのプロファイリング

メソッド・モードを使用すると、メソッドおよびクラスのメトリックを表示できます。メソッド・レポートには、「フォワード・コール」、「ホット・スポット」、「リバース・コール」、「デルタ値の表示」および「スレッドの選択」別にデータを表示するためのアイコンが用意されています。

メソッド・モードでは、メソッドおよびクラスのメトリックが提供されます。メソッド・レポートでは、該当するアイコンをクリックすると、「フォワード・コール」「ホット・スポット」および「リバース・コール」ごとに表示できます。「デルタ値の表示」および「スレッドの選択」を選択することもできます。
  • デルタ値の表示-このアクションは絶対値から増分値に切り替えます。ビューを切り替える前に表示される値は記憶されますが、新規に選択された瞬間から新しいビューで変更が表示されます。このアイコンを再度クリックすると、結果が絶対値に戻されます。

  • スレッドの選択-この操作はライブ結果や保存されたスナップショットで使用できるスレッドを表示し、結果を表示する特定のスレッドの選択を可能にします。この機能は、デスクトップ・アプリケーションでEDTの遅さを追跡している場合、またはサーバー・アプリケーションでワーカー・スレッドを分析している場合に特に有用です。一部のスレッドが選択され、「すべてのスレッドの表示」オプションのために無効になっている場合、「選択したスレッドのマージ」オプションが有効になります。この機能は、結果を選択したスレッドから単一のツリーにマージします。

さらに、表示する列を選択できます。オプションは、「合計時間」「合計時間(CPU)」「選択済」および「ヒット」または「呼出し」(セッション構成に応じて)です。

プロファイリング・メソッド・セッションを起動するには、「プロファイラの起動について」を参照してください

図10-7はメソッド・セッションのスナップショットを表示します。

図10-7 メソッド・セッション

図10-7の説明が続きます
「図10-7 メソッド・セッション」の説明

特定メソッドのプロファイリング

メソッド・セッションの範囲を絞り込み、特定のメソッドまたはクラスをプロファイルする手順を使用してください。

次のステップに従って、メソッド・セッションの範囲を絞り込み、特定のメソッドまたはクラスをプロファイリングできます。

  1. プロファイリング設定バーを表示するアイコン アイコンをクリックします。

    新しい設定バーが表示されます。

  2. 「プロファイル」ドロップダウンで、該当するものを選択します。
  3. 「プラス」アイコンをクリックし、クラスまたはメソッドを追加します。

    「クラスの選択」または「メソッドの選択」ウィンドウが表示されます。

  4. 「クラスの選択」ウィンドウでクラスを選択するには、「プロジェクト」「パッケージ」および「クラス」を選択し、「OK」をクリックします。

    「メソッドの選択」ウィンドウでメソッドを選択するには、「プロジェクト」「パッケージ」「クラス」および「メソッド」を選択し、「OK」をクリックします。

    あるいは、メソッドまたはクラスを右クリックして選択します。この機能は、プロファイルの結果およびスナップショット・ウィンドウで使用できます。

オブジェクトのプロファイリング

オブジェクト・モードを使用すると、プロジェクトに割り当てられているクラスのリストを表示できます。

オブジェクト・モードでは、ライブ・インスタンスおよびバイト・アロケーションを含むプロジェクトに割り当てられているクラスのリストが提供されます。ページの右上隅にあるクリックしてクラスを選択しますアイコンをクリックすると、プロファイルされるクラスを選択できるドロップダウン・メニューにアクセスします。「すべてのクラス」モードは、「仮想マシン」ヒープ上にあるすべてのクラスおよびオブジェクトを表示します。「プロジェクトのクラス」フィルタでは、プロジェクトで定義されているクラスのみを表示できます。

プロファイリング・オブジェクト・セッションを起動するには、「プロファイラの起動について」を参照してください

図10-8はオブジェクト・セッションのスナップショットを表示します

図10-8 オブジェクト・セッション

図10-8の説明が続きます
「図10-8 オブジェクト・セッション」の説明

特定オブジェクトのプロファイリング

クラスのコンテキスト・メニューに表示される「プロファイル・クラス」オプションを使用して、特定のクラスをプロファイルします。

クラスを右クリックして、「プロファイル・クラス」を選択することで、特定のクラスをプロファイルするように選択できます。「ライブ・オブジェクトのみ追跡」および「割当ての深さを制限」チェック・ボックスが表示されます。

ライブ・オブジェクトのみ追跡— 選択されると、ライブ・オブジェクトのみを追跡します。選択されていない場合、アプリケーションによって割り当てられているすべてのオブジェクトを追跡します。

割当ての深さを制限— 指定した数にスタックの深さの割当てを制限します。

クラスを選択した後、変更を送信するプロファイリング・セッションが進行している間に、右側にある「適用」ボタンをクリックします。図10-9に示すように、この操作はビューをクリアして、選択したクラスのみを指定します

図10-9 オブジェクト・セッション - 選択済クラス・ビュー

図10-9の説明が続きます
「図10-9 オブジェクト・セッション - 選択済クラス・ビュー」の説明

スレッドのプロファイリング

スレッド・モードを使用して、アプリケーション・スレッド・アクティビティに関する詳細情報を表示します。スレッドのプロファイリング・セッションに表示される「実行中のスレッド」リストで使用可能なオプションにより、スレッドをカスタマイズします。

スレッド・モードでは、アプリケーション・スレッド・アクティビティに関する詳細な情報を表示します。

プロファイリング・スレッド・セッションを起動するには、「プロファイラの起動について」を参照してください

図10-10に、スレッド・セッションのスナップショットを示します

図10-10 スレッド・セッション

図10-10の説明が続きます
「図10-10 スレッド・セッション」の説明

さらに、「実行中のスレッド」ドロップダウン・リストにアクセスして、次の使用可能なオプションを選択することでモニターするスレッドをカスタマイズできます。「すべてのスレッド」「実行中のスレッド」(デフォルト)、「終了スレッド」および「選択されたスレッド」

ロックのプロファイリング

ロック・モードを使用して、ロックされたスレッドおよびロックをモニターおよび保持しているスレッドの詳細を表示します。ロックのプロファイリング・セッションでは、「スレッド」リストにロックされたスレッドが表示され、「モニター」に他のスレッドをロックしているスレッドが表示されます。

ロック・モードでは、ロックされたスレッドおよびロックをモニターおよび保持しているスレッドの詳細を表示できます。

ロック・セッションのプロファイリングを起動するには、「プロファイラの起動について」を参照してください

図10-11はロック・セッションのスナップショットを表示します

図10-11 ロック・セッション

図10-11の説明が続きます
「図10-11 ロック・セッション」の説明

セッション・ウィンドウでは、「スレッド」ドロップダウン・リストの「スレッド」または「モニター」を選択できます。ロックされたスレッドを表示するには、「スレッド」を選択します。ノードを開いてロックの所有者を表示します。他のスレッドをロックしているスレッドを表示するには、「モニター」を選択します。

プロファイリング・セッション実行中の追加機能

プロファイラ・セッションの実行中、プロファイラ・ウィンドウのツールバーには、「スレッド・ダンプ」、「ヒープ・ダンプ」、「GC」、「スナップショット」および「収集結果をリセット」などの実際のプロファイラ・モードに関係するアクションが表示されます。

プロファイラ・セッションが進行中、実際のプロファイラ・モードに関連する追加処理がプロファイラ・ウィンドウのツールバーで使用できます。次のアクションは常に使用できます。

スレッド・ダンプ—すべてのアクティブ・スレッドのテキストのダンプを作成し、プロファイルされたアプリケーションをモニターします。ダンプを取得した時点でどのメソッドが実行されているかをスレッドごとに表示します。この情報は、アプリケーションが今何を行っているかを表示する際に役立ちます。スレッド・ダンプには、ロック、ロックを保持しているスレッドおよびロックの取得を待っているスレッドに関する情報も表示されます。このデータはデッドロックをデバッグする際に必須です。「スレッド・ダンプ」を取得するには、プロファイリング・セッション中に「スレッド・ダンプ」アイコンをクリックします。スナップショットの取得に関する詳細は、「プロファイリング・データのスナップショットの取得およびアクセス」を参照してください

ヒープ・ダンプ—プロファイルされたプロセスの現在のヒープ・コンテンツのイメージを.hprof形式保存し、オプションでヒープ・ブラウザで開きます。「ヒープ・ダンプ・データの取得」を参照してください

GC—プロファイルされたプロセスのJVMを要求し、ガベージ・コレクションを呼び出します。ガベージ・コレクションのJVM動作は、JVM仕様では定義されていません。どこかの時点でガベージ・コレクションを実行する必要がありますが、即座に実行するかまったく実行しないか何も保証しません。

さらに、メソッドまたはオブジェクトをプロファイリングする際には、次の処理が使用可能です。

スナップショット—メソッドまたはオブジェクトに関連する現在収集されているすべてのプロファイリング・データのスナップショットを作成します。スナップショットは別のウィンドウで開き、プロジェクトまたは外部ファイルに保存できます。「プロファイリング・データのスナップショットの取得およびアクセス」を参照してください

収集結果をリセット—メソッドまたはオブジェクトに関連する現在収集されているすべてのプロファイリング・データをクリアします。

プロファイラ・ウィンドウのツールバーに表示されているその他の処理は実際のプロファイリング・モードに固有です。複数のプロファイリング・モードがプロファイリング・セッションでアクティブな場合、ツールバーは現在表示されているモードで使用できる処理を表示します。