目次


Eclipse を使ってリモートで Java アプリケーションをデバッグする

Eclipse IDE の強力さを利用して Java アプリケーションのデバッグ作業を分散させる

Comments

リモートでのデバッグは、アプリケーション開発 (例えば開発プラットフォームをホストできないローエンド・マシン用のプログラムを開発する場合など) において、あるいはサービスを停止できない Web サーバーなどの専用マシン上のプログラムをデバッグする場合において便利です。リモートでのデバッグが有効なその他の例としては、Java アプリケーションが実行されるマシンのメモリーや CPU の処理能力が限られている場合 (モバイル機器など) や、アプリケーションの環境と開発環境を分離したい場合などがあります。

前提条件

まだ Eclipse V3.4 (Ganymede) をダウンロードしていない人は、すぐにダウンロードしてください。Ganymede ではソケットをリッスンするコネクターが Remote Java Application 起動構成タイプに追加されています。ソケットをリッスンする Eclipse の新しいコネクターを使うと、Java デバッガーを起動して特定のソケットで接続をリッスンすることができます。そしてコマンドライン・オプションを使ってデバッグ対象のプログラムを起動し、そのプログラムをデバッガーに接続するのです。Ganymede がリリースされる前までは、ソケット接続用コネクターしか提供されておらず、デバッグ対象のプログラムが実行されるマシンはプログラムを実行すると同時にデバッガーによって接続されるデバッグ・ホストでなければなりませんでした。しかし、モバイル機器はメモリーや CPU の処理能力が不十分なため、ホストとして使うことは非現実的でした。

リモート・デバッグを行うためには、JVM (Java Virtual Machine) V5.0 以降を使用する必要があります (IBM® J9 や、Sun Microsystemsの JDK (Java SE Development Kit) など)。この記事では、Eclipse のデバッグ機能をそれぞれ詳細に取り上げるのではなく、リモート・デバッグに焦点を絞ります。Eclipse でのデバッグについて、また必要なソフトウェアの入手方法に関しては「参考文献」を参照してください。

JPDA の紹介

Sun Microsystems の JPDA (Java Platform Debugger Architecture) 技術はマルチ階層のアーキテクチャーであり、あらゆる状況において Java アプリケーションを容易にデバッグすることができます。JPDA は、2 つのインターフェース (JVM Tool Interface と JDI)、プロトコル (Java Debug Wire Protocol)、そしてそれらを結びつける 2 つのソフトウェア・コンポーネント (バック・エンドとフロント・エンド) で構成されており、あらゆる環境のデバッガーで使用できるように設計されています。また、JPDA はデスクトップ・システム専用ではなく、組み込みシステムでも適切に動作することができます。

JVMTI (JVM Tool Interface) はデバッグ用に VM が用意しなければならないインターフェースを定義します (編集者注: Java V1.4 で使用されていた JVMDI は、Java V5 から JVMTI に置き換えられています)。JDWP (Java Debug Wire Protocol) はデバッグ対象のプロセスとデバッガーのフロント・エンド (JDI を実装する Eclipse、Borland Jbuilder、その他多数) との間で交換されるデバッグ情報やデバッグ・リクエストのフォーマットを記述します。Sun の JPDA 仕様では、デバッグ対象のプログラムはよく debuggee と呼ばれます。JDI はリモート・デバッグに使用される情報やリクエストを定義するための上位レベルのインターフェースです。このアーキテクチャーの構造は以下のとおりです。

リスト 1. Java Platform Debugger Architecture の構造
             Components                      Debugger Interfaces

                 /    |--------------|
                /     |     VM       |
 debuggee -----(      |--------------|  <---- JVMTI - Java VM Tool Interface
                \     |   back-end   |
                 \    |--------------|
                 /           |
 comm channel --(            |  <------------ JDWP - Java Debug Wire Protocol
                 \           |
                 /    |--------------|
                /     |  front-end   |
 debugger -----(      |--------------|  <---- JDI - Java Debug Interface
                \     |      UI      |
                 \    |--------------|

したがって JPDA に基づくサードパーティーのツールや VM であれば、どのようなものであっても問題なく互いに協調動作するはずです。このようにクライアント・サーバー型のアーキテクチャーが採用されているため、このプラットフォームを実行するローカル・ワークステーションから Java プログラムをデバッグすることも、さらにはネットワーク上のリモート・コンピューターから Java プログラムをデバッグすることもできます。

デバッグのシナリオについて説明する前に、JPDA 仕様で使われる、コネクターとトランスポートという 2 つの用語を紹介する必要があります。コネクターは JDI を抽象化したものであり、デバッガー・アプリケーションとターゲット VM との間の接続を確立するために使われます。トランスポートはフロント・エンドとバック・エンドとの間でアプリケーションがデータにアクセスしたりデータを送信したりする方法を定義します。コネクターは利用可能なトランスポート・タイプと接続モードに「マッピング」されます。Sun による JPDA のリファレンス実装では、Microsoft® Windows® 用にソケット・トランスポートと共有メモリー・トランスポートという 2 つのトランスポート機構が提供されています。利用可能なコネクターは次のとおりです。

  • ソケット接続用コネクター
  • 共有メモリー接続用コネクター
  • ソケットをリッスンするコネクター
  • 共有メモリーをリッスンするコネクター
  • コマンドラインから起動されるコネクター

デバッガー・アプリケーションとターゲット VM との間で接続を確立する際には、一方がサーバーとして動作し、接続をリッスンします。その後、もう一方がリスナーに接続することで、両者の接続が確立されます。接続においては、デバッガー・アプリケーションまたはターゲット VM のどちらかがサーバーとして動作することができます。プロセス同士の通信は 1 台のマシン上で行われる場合もあれば、異なるマシン間で行われる場合もあります。

Java プログラムをリモートでデバッグする際の問題は、デバッガーのフロント・エンドではなくリモートの Java バック・エンドにあります。残念ながら、これについて Eclipse のヘルプ・システムにはあまり情報がありません。実際、JDI の実装は Eclipse により行われ、JVMTI の実装は Java ランタイム環境により行われます。唯一、皆さんが関与するのは、JVMTI および JDI と通信するための情報を含む JDWP です。JDWP には、リモート Java アプリケーション用のアプリケーションを呼び出すために追加された多くの引数があります。以下に示すのはこの記事で使用する引数です。

-Xdebug
デバッグ機能を有効にします。
-Xrunjdwp:<sub-options>
ターゲット VM に JDWP の実装をロードします。この実装はトランスポートと JDWP プロトコルを使って別のデバッガー・アプリケーションと通信します。具体的なサブオプションを以下に示します。

Java V5 から、-Xdebug と -Xrunjdwp の代わりに -agentlib:jdwp オプションを使うことができます。しかし V5 よりも前の VM に接続しなければならない場合には、-Xdebug と -Xrunjdwp が唯一の選択肢となります。以下に示すのは -Xrunjdwp サブオプションの簡単な説明です。

transport
通常はソケット・トランスポートが使われます。しかし Windows プラットフォームでは、共有メモリー・トランスポートを使うこともできます (共有メモリー・トランスポートが利用できる場合)。
server
この値が y の場合、ターゲット・アプリケーションは接続先となるデバッガー・アプリケーションをリッスンします。それ以外の場合には、ターゲット・アプリケーションは指定されたアドレスにあるデバッガー・アプリケーションに接続します。
address
この値は接続のためのトランスポート・アドレスです。server の値が n の場合には、このトランスポート・アドレスにあるデバッガー・アプリケーションへの接続が試行されます。それ以外の場合には、このポートで接続をリッスンします。
suspend
この値が y の場合、ターゲット VM はデバッガー・アプリケーションが接続されるまで中断されます。

デバッグのための各設定の詳細な説明は JPDA のドキュメントを参照してください (「参考文献」を参照)。

リスト 2 は、VM をデバッグ・モードで起動してポート 8765 でソケット接続をリッスンする方法の例を示しています。

リスト 2. ターゲット VM がデバッグ・サーバーとして動作する
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8765

リスト 3 は、ホスト 127.0.0.1 のポート 8000 のソケットを使用して実行中のデバッガー・アプリケーションに接続する方法を示しています。

リスト 3. ターゲット VM がデバッグ・クライアントとして動作する
-Xdebug -Xrunjdwp:transport=dt_socket,address=127.0.0.1:8000

Eclipse のリモート・デバッグ機能

Eclipse はグラフィカルな Java デバッガーのフロント・エンドです。JDI は org.eclipse.jdt.debug バンドルに実装されています。この記事では JDI の実装の詳細については説明しません。Eclipse の JDT と Java JDI 技術については「参考文献」を参照してください。

最初に、どの Eclipse コネクターを使うのかを知る必要があります。Eclipse で提供されているリモート接続タイプを知るためには、Remote Java Application に起動構成を追加します。そのためには Eclipse メニューから Run (実行) > Debug Configurations... (デバッグの構成...) の順に選択し、次にドロップダウン・リストからコネクターを選択します。Ganymede では次の 2 つのコネクターが提供されています。

  • Socket Attach
  • Socket Listen

Socket Listen コネクターを選択した場合には、Eclipse VM はリモート Java アプリケーションによって接続されるホストになります。Socket Attach コネクターを選択した場合には、ターゲット VM がホストになります。どちらのコネクターを使用するかはユーザーが選択しますが、どちらを選択してもアプリケーションのデバッグに関する違いはありません。大まかな指針としては、必要な計算リソースから考えて、より高速で強力なコンピューターの方をVM デバッグ・ホストとして使用することです。

Java アプリケーションをデバッグする前に、リモート・アプリケーションに対するデバッグ・オプションがすべて有効になっていることを確認する必要があります。デバッグ情報が得られないと、「Debug information is not available (デバッグ情報がありません)」や「Unable to install breakpoint due to missing line number (行番号がないためブレークポイントを設定できません)」というようなエラー・メッセージが表示されます。デバッグ情報に関する設定を Eclipse メニューから変更するためには、Window (ウィンドウ) > Preferences (設定) > Java > Compiler (コンパイラー) の中で設定されている内容を変更します。

図 1. Eclipse のデバッグ・オプション
Eclipse のデバッグ・オプション
Eclipse のデバッグ・オプション

アプリケーションをリモートでデバッグする

これで、リモートでアプリケーションのデバッグを開始する準備が整いました。では順を追って説明しましょう。

1. 簡単なクラスを持つ Java プロジェクトを作成します。
デバッグ用に簡単なクラスを作成します。リスト 4 はそのサンプル・コードを示しています。
リスト 4. デバッグ用のサンプル・コード
package com.ibm.developerWorks.debugtest;

public class test {

public static void main(String[] args) {
System.out.println("This is a test.");
}
}
2. ブレークポイントを設定します。
コードの中にブレークポイントを設定します。この例ではブレークポイントを、System.out.println("This is a test."); の行に設定します。
図 2. Eclipse でブレークポイントを設定する
Eclipse でブレークポイントを設定する
Eclipse でブレークポイントを設定する
3. アプリケーションをローカルでデバッグします。
アプリケーションをデバッグする前に、図 1 に示したデバッグ・オプションがこのプロジェクトで有効になっていることを確認します。ローカルでのアプリケーションのデバッグは必要ありませんが、これにより、すべてのデバッグ情報が利用可能かどうかを確認することができます。この Java プロジェクトを右クリックして Debug As (デバッグ) を選択し、さらに Java Application (Java アプリケーション) を選択します (図 3)。アプリケーションの実行がブレークポイントで停止すれば、デバッグ情報が適切に提供されているということです。この後も、続けてデバッグ機能 (デバッグ・スタックや変数の表示、ブレークポイントの操作など) を使うことができます。
図 3. アプリケーションをローカルでデバッグする
アプリケーションをローカルでデバッグする
アプリケーションをローカルでデバッグする
4. Java プロジェクトをエクスポートします。
このアプリケーションをデバッグのターゲットとして使用します。Java プロジェクトを右クリックして Export (エクスポート) を選択し、さらに Java を選択します。次にプロジェクトのエクスポート・ファイルとして JAR file (JAR ファイル)Runnable JAR file (実行可能 JAR ファイル) のいずれかを選択します。指定された場所に JAR ファイルが作成されます。Java ソースがターゲット・アプリケーションと一致しない場合にはデバッグ機能が正しく動作しないので注意してください。
5. Java アプリケーションを手動で実行します。
コンソールを開いてアプリケーションを手動で起動し、Java ランタイム環境が適切に構成されていることを確認します。
リスト 5. Java アプリケーションを呼び出す例
java -jar test.jar
6. アプリケーションをリモートでデバッグします。
JAR ファイルをリモート・コンピューターの適当な場所にコピーして (あるいは同じマシン上にコピーしても構いません)、デバッグ・サーバーを呼び出し、デバッグ・サーバーにクライアントを接続します。この簡単な Java アプリケーションはデバッグ・サーバーとして、あるいはデバッグ・クライアントとして動作することもできます。構成に応じて、Eclipse の中で Socket Attach または Socket Listen のいずれかの接続タイプを選択することができます。次の 2 つのセクションでは、このアプリケーションをサーバーとして実行する方法とクライアントとして実行する方法を説明します。

ターゲット VM がデバッグ・サーバーとして動作する

次の例では、Java アプリケーションがリモート・サイドで呼び出されてデバッグ・サーバーとして動作し、ポート 8000 でソケット接続をリッスンします。ターゲット VM はデバッガーが接続されるまで中断されます。

リスト 6. Eclipse の Socket Attach モードで VM を呼び出す例
java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address="8000" -jar 
     test.jar

リモート起動構成を使って Eclipse を起動し、リモート・アプリケーションのターゲット VM のアドレスを指定します。そのためには、Eclipse のメニューで Run (実行) > Debug Configurations (デバッグの構成) の順にクリックし、さらに Remote Java Application (リモート Java アプリケーション) をダブル・クリックします。新たに作成された起動構成で、ターゲット・アプリケーションの IP とポート番号を指定します。同じマシンでリモート・アプリケーションを実行する場合には、単純にホスト IP に localhost または 127.0.0.1 と指定します。

図 4. Socket Attach 接続の構成
Socket Attach 接続の構成
Socket Attach 接続の構成

Allow termination of remote VM (リモート VM の終了を許可する) オプションを選択すると、アプリケーションのデバッグ中に接続先の VM を終了できるようになります。

図 5. Eclipse の Terminate ボタン
Eclipse の Terminate ボタン
Eclipse の Terminate ボタン

ターゲット VM がデバッグ・クライアントとして動作する

2 番目の例では、デバッグ・クライアントとして動作する簡単な Java アプリケーションと、デバッグ・サーバーとして動作するデバッガー・フロント・エンドを使います。Eclipse は Socket Listen モードの接続タイプを使ってリッスンするため、先にデバッグのフロント・エンドを起動して特定のポートをリッスンするようにしておく必要があります。図 6 は Socket Listen 接続を設定するためのサンプル構成を示しています。

図 6. Socket Listen 接続の構成
Socket Listen 接続の構成
Socket Listen 接続の構成

Eclipse の Debug ボタンをクリックすると、ステータス・バーに「waiting for vm to connect at port 8000... (VM によるポート 8000 への接続を待機中)」というメッセージが表示されます。このメッセージが表示されたら、リモート・アプリケーションを起動します。リスト 7 では Java アプリケーションをデバッグ・クライアントとして起動し、ホスト127.0.0.1 のポート 8000 というソケットを使って実行中のデバッガー・アプリケーションに接続する方法を示しています。

リスト 7. Eclipse の Socket Listen 接続で VM を呼び出す例
    java -Xdebug -Xrunjdwp:transport=dt_socket,address=127.0.0.1:8000,suspend=y 
         -jar test.jar

すべてが適切に動作すると、アプリケーションのデバッグをサポートするデバッグ・パースペクティブが表示され、リモート Java アプリケーションの実行が正常に停止されます。これは先ほど説明したローカルでのデバッグでのステップ 3 と似ています (図 3)。この段階まで来ると、ブレークポイントや値の設定、ステップ実行など、標準的なデバッグ機能を使うことができます。

この記事では、Eclipse に組み込まれているリモート Java アプリケーション構成タイプを使ってリモートでアプリケーションをデバッグする方法を説明しました。ここではリモート・デバッグ機能を呼び出すために Java アプリケーションを設定する方法を紹介し、また Eclipse で提供されているコネクターについて説明しました。そして最後に、この技術をプロジェクトに適用する方法についても学びました。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source, Java technology
ArticleID=365786
ArticleTitle=Eclipse を使ってリモートで Java アプリケーションをデバッグする
publish-date=12092008