デバッグ

このセクションでは、JRun を使用して開発した Web アプリケーションをデバッグする際に使用できる、一般的なタスクおよびテクニックについていくつか説明します。次のようなセクションがあります。

JRun によるデバッガの起動

JRun アプリケーションをデバッグするための最も基本的な方法の 1 つは、Java デバッガ コマンド jdb の制御のもとで JRun を起動する方法です。jdb のもとで JRun を起動すると、ブレーク ポイントおよびシングル ステップの設定、スレッドに関する情報の取得、メモリ使用の検査、およびその他のさまざまなデバッグ操作を行うことができます。

jdb コマンドを使用して JRun を起動するには、使用するシステムの CLASSPATH 環境変数に、次のファイルを追加する必要があります。

Windows では、次のコマンドを使用して、jdb のもとで default JRun サーバーを起動します。

jdb JRun c:\progra1\Allaire\JRun\servers\default

jdb ユーティリティが Windows のディレクトリ名「program files」に含まれているスペースを解釈できないこともあるため、省略形の progra1 が必要です。UNIX マシンでは、起動する JRun サーバーへのパスを使用します。

スタック トレース

アプリケーションのデバッグに役立つ方法として、スタック トレースを取得する方法があります。Java スタック トレースには、JVM のスレッドおよび監視に関する情報が含まれています。実際に、お客様の問題を解決する方法の一部として、Allaire カスタマ サポートでは、スタック トレースを生成して、電子メールで Allaire に送信していただくようにお客様にお願いしています。

通常、スタック トレースは、デッドロック状態の原因を特定するために使用します。同時に発生する多数の要求を処理するため、JRun はマルチスレッド モデルを使用します。マルチスレッド環境では、スレッドがいつでもリソースを利用できるように、特定のリソースへのアクセスはロックによって制御されます。あるスレッドが 2 番目のスレッドからリソースを取得するために待機しなければならず、2 番目のスレッドも最初のスレッドからリソースを取得するために待機するといった状況が発生します。この状況は、デッドロックと呼ばれます。

次の例は、デッドロックを含むスタック トレースからの抜粋です。

t@37 waiting to lock object@0xdbdf15c8:"oracle/jdbc/driver/
OracleCallableStatement" which is locked by t@529 
t@529 waiting to lock object@0xdc030470:"oracle/jdbc/driver/
OracleConnection" which is locked by t@37 

このように、スレッド 37 および 529 は、お互いに相手のスレッドがリソースを解放するのを待っています。両方のスレッドが待機しているため、どちらのスレッドも相手のスレッドが要求するリソースを解放することはできません。この場合、両方のスレッドは永久に待ち続けます。

次のセクションでは、JRun でサポートされているオペレーティング システム用のスタック トレースを取得する方法について説明します。

Allaire では、Java スタック トレースの内容の解釈に関する文書を Knowledge Base で公開しています。知識ベースの記事番号 12406 は、次の URL で参照できます。

http://allaire.com/Support/KnowledgeBase/SearchForm.cfm

Windows のスタック トレース

Sun または IBM の JVM を使用した Windows システムで稼動する JRun からスタック トレースを取得するには、次の手順を実行します。

  1. JRun を実行するための Java 実行可能ファイルとして、javaw.exe ではなく、java.exe を使用していることを確認します。java.exe では JRun サーバーの起動時に DOS ウィンドウが開きますが、javaw.exe では Java アプリケーションの実行時に DOS ウィンドウが開きません。

    JMC で [サーバー名] > [Java の設定] > [Java 実行ファイル] プロパティを使用 して、java.exe を設定します。サーバー名には、JRun サーバーの名前を指定します。

  2. JRun サーバーを起動します。

    空白の DOS ウィンドウが開きます。

  3. DOS ウィンドウをアクティブにし、Ctrl-Break キーを押して、スタック トレースが {JRun home dir}/logs/servername-err.log ファイルに書き込まれるようにします。

    メモ

    このファイルの名前は、java.System.err プロパティで定義されます。ファイル名 を変更するには、JRun サーバーの local.properties ファイルでこのプロパティ を変更します。このプロパティの詳細については、第 41 章 を参照してください。


    または、DOS ウィンドウの [閉じる] ボタン (DOS ウィンドウの右上隅にある [X] アイコン) をクリックして、スタック トレースを開始することもできます。DOS ウィンドウは閉じませんが、ポップアップ ウィンドウに次のメッセージが表示され ます。

    この Windows アプリケーションは [アプリケーション終了] に応答できません。

    [アプリケーション終了] を選択すると JRun は停止し、[キャンセル] を選択すると JRun は実行を続けます。

  4. メモ帳、ワードパッド、またはほかのテキスト エディタを起動して、{JRun home dir}/logs/servername-err.log ファイルに含まれるスタック トレース情報を読み取ります。

UNIX/Solaris スタック トレース

UNIX/Solaris の場合、既定では、スタック トレースを保持する JRun/logs/{server}-err.log という名前のファイルが定義されます。{server} は、JRun サーバーの名前です。

次の手順に従って、スタック トレースを取得します。

  1. top コマンドを使用して java プロセスのプロセス ID 番号を特定するか、ps -ef コマンドの出力時に grep コマンドを使用します。次の例では、grep および ps コマンドを使用しています。
    ps -ef | grep java 
    
  2. kill -QUIT または kill -3 コマンドを使用して、quit 信号を java プロセス ID に送信します。次に例を示します。
    kill -3 jrunjavaID
    

    一部の UNIX/Solaris プラットフォームでは、使用する JDK によって、Java プロ セスを開始したモニタまたはターミナル ウィンドウに Java スタック トレースが 直接送信されない場合があります。スタック トレースの出力を別の出力先に転送 する機会はありません。唯一の方法として、トレースをモニタまたはウィンドウに ダンプして、コピーしたトレースを vi や Emacs などのエディタを実行している 別のターミナル ウィンドウに貼り付けます。

Linux

Sun/Blackdown JVM を使用した Linux システムに関するスタック トレースを取得するには、"UNIX/Solaris スタック トレース" に記載されている手順を実行してください。

IBM JVM は、quit 信号が送信された JRun サーバーのルート ディレクトリに javacore.txt ファイルを作成して、kill -QUIT または kill -3 に応答します。たとえば、default JRun サーバーの場合、このディレクトリは、既定では /opt/JRun/servers/default になります。

次の手順に従って、スタック トレースを取得します。

  1. top コマンドを使用して java プロセスのプロセス ID 番号を特定するか、ps -ef コマンドの出力時に grep コマンドを使用します。次の例では、grep および ps コマンドを使用しています。
    ps -ef | grep java 
    
  2. kill -QUIT または kill -3 コマンドを使用して、quit 信号を java プロセス ID に送信します。次に例を示します。
    kill -3 jrunjavaID
    

コア ダンプの処理 (UNIX システムのみ)

アプリケーションがコア ダンプを引き起こすと、オペレーティング システムはアプリケーションを起動したディレクトリにコア ファイルを書き込みます。


メモ

コア ダンプは、UNIX システムでのみ発生し、Windows では発生しません。


JRun は Java で記述されているため、JRun でエラーが発生した場合は、常に Java 例外が返され、JRun 自体がコア ダンプを引き起こすことはありません。JRun に関係するコア ダンプは通常、次の理由によって JVM またはアプリケーション自体によって引き起こされます。

  1. JVM にバグがある。これは通常、JVM がオペレーティングと対話するときに発生します。JVM 内のバグはコア ダンプを引き起こす可能性があります。
  2. JRun アプリケーションが、Java Native Interface (JNI) などを使用してエラーのあるネイティブ コードを使用している。たとえば、ODBC ドライバを呼び出す Type 1 JDBC ドライバを使用してデータベースにアクセスすると、ドライバのネイティブ コードがスレッド セーフではないため、デッドロックおよびコア ダンプを引き起こします。

Allaire では、コア ダンプに関する文書を知識ベースで公開しています。知識ベースの記事番号 15437 は、次の URL で参照できます。

http://allaire.com/Support/KnowledgeBase/SearchForm.cfm

メモリ不足エラーの処理

JVM の各インスタンスは、ヒープと呼ばれるスレッドで共有されるすべてのオブジェクトに対してメモリの割り当てを使用します。実行時に、JVM はすべてのクラス インスタンスおよび配列に対してヒープからメモリを割り当てます。作成したサーブレットまたは JSP ページによって、エラー メッセージ java.lang.OutOfMemoryError が JRun ログファイルまたはスタック トレースに書き込まれた場合は、使用する JVM の最大ヒープ サイズを増やす必要があります。


メモ

作成するアプリケーションで OutOfMemoryError が発生しないように注意してくだ さい。一般的に、これらのエラーは予測できません。また、これらのエラーが発生した 場合、復旧することもできません。このエラーが発生する前に、JVM ではメモリ不足 エラーが発生し、ガーベッジ コレクタがメモリを解放して処理を続けることができなく なります。


OutOfMemoryError は、新しいオブジェクトにメモリを割り当てる無限ループなどのプログラミング エラーによって発生する可能性もあります。このタイプのプログラミング エラーは、JVM に割り当てるメモリの量にかかわらずエラーを引き起こします。

既定のヒープ サイズは JVM によって異なります。ただし、ほとんどの JVM では、ヒープの最小サイズおよび最大サイズを変更でき、これらの設定の既定値が用意されています。次の一覧に、Sun と IBM の両方の JVM に最も一般的なヒープ設定を示します。ほとんどの JVM ベンダは、Sun のルールに従ったヒープ サイズの既定値を採用しています。

最大ヒープ サイズを増やすには

  1. JMC で、[サーバー名] > [JVM の設定] > [Java 引数] プロパティを使用して、ヒープ サイズを設定します。

    メモリ設定の既定の単位はバイトです。数字がキロバイトまたはメガバイトで解釈されるように指定するには、接尾辞 k または m を追加する必要があります。


    注意

    これらの設定の指定に不正な構文を使用すると、JVM が起動しなくなる可能性があり ます。これらのパラメータを変更して、JRun の再起動に失敗した場合は、
    global.properties ファイルまたは local.properties ファイルの設定を手作業で 編集する必要があります。


    次の例は、Java バージョン 1.2 の JVM の最小ヒープ サイズ、最大ヒープ サイズ、およびその他の値を設定します。

    -Xms64m -Xmx128m -Xrs -Djava.compiler=NONE 
    

    正確な構文および既定値については、それぞれ対応する JDK のマニュアルを参照してください。


    メモ

    Allaire 知識ベースの記事番号 13940 では、この状況についても説明しています。 Allaire 知識ベースの詳細については、http://allaire.com/Support/KnowledgeBase/SearchForm.cfmを参照してください。


    クライアント/サーバー間の通信の監視

    JRun には HTTP スニファ メカニズムが用意されています。このメカニズムにより、Web クライアントと HTTP サーバーの通信を監視して、その情報を JRun ログ ファイルに転送できます。スニファ メカニズムを使用して、HTTP 要求/応答のヘッダ部分とコンテンツ部分の両方を追跡できます。要求、Web サーバーからのクッキー設定、およびその他の要求/応答コンテンツの一部として、クライアントから渡されるパラメータを調べることができるため、スニファ メカニズムはアプリケーションをデバッグする際に役に立ちます。

    スニファ メカニズムは HTTP ポートを監視して、クライアント要求を検出します。クライアントがそのポートに対して HTTP 要求を作成すると、スニファ メカニズムはその要求を読み取り、ログに記録して、要求をターゲット Web サーバーに転送します。スニファは、Web サーバーからの応答を待ち、受け取った応答をログに記録して、応答をクライアントに転送します。

    スニファ メカニズムが要求を処理するために、要求をスニファの HTTP ポートに転送します。既定では、スニファ ポートは 8101 に設定されます。次に、スニファはその要求を処理するために Web サーバーに転送します。したがって、既定のスニファ ポートへの URL は次のような形式になります。

    http://localhost:8101/resource
    

    次の形式を使用すると、スニファ メカニズムをバイパスして、同じ要求を Web サーバーに直接転送できます。

    http://localhost/resource
    

    スニファ メカニズムは複数の要求を同時に処理できます。その結果、異なる要求からのログ メッセージがログ ファイルにインターリーブされます。このため、スニファ メカニズムでは、ログ ファイルの各行の先頭に固有の要求 ID を付けて要求を識別します。

    スニファ メカニズムの設定

    スニファ メカニズムを設定するには、プロパティ ファイルを使用します。JRun 管理コンソール (JMC) からスニファ メカニズムを制御することはできません。

    JRun の 1 つのインストールに関連するすべての JRun サーバーのスニファ メカニズムのための既定の設定は global.properties ファイルに格納されています。通常、global.properties ファイルは変更しません。個々の JRun サーバーの設定を変更する場合は、local.properties ファイルのそのサーバーの設定を変更します。

    global.properties ファイルでの既定のプロパティ設定は次のとおりです。

    sniffer.class=allaire.jrun.http.Sniffer
    
    sniffer.port=8101 
    sniffer.loglevel=info 
    sniffer.logcontent=true 
    sniffer.target.host=localhost 
    sniffer.target.port=80 
    

    これらのプロパティは、次のオプションを指定します。

    既定では、JRun のスニファ メカニズムは無効になっています。スニファ メカニズムを有効にするには、スニファ メカニズムを JRun サービスの一覧に追加する必要があります。サービスは、global.properties または local.properties ファイルのいずれかで有効にできます。サービスを global.properties で指定すると、すべての JRun でスニファ メカニズムが有効になります。サービスを local.properties で指定すると、そのファイルに関連する JRun サーバーについてのみ、スニファ メカニズムが有効になります。

    global.propeties を使用してスニファ メカニズムを有効にするには、次の例で示すように、スニファ サービスを jrun.services プロパティに追加します。

    # 開始するサービスの一覧
    
    jrun.services=scheduler,logging,monitor,license,control,{servlet.servic
    es},{ejb.services},sniffer 
    

    local.propeties を使用してスニファ メカニズムを有効にするには、
    global.properties から現在のサービスの一覧をコピーして JRun サーバーの local.properties ファイルに貼り付け、sniffer をサービスの一覧の最後に追加します。

    これらのプロパティの詳細については、"スニファ メカニズムのプロパティ" を参照してください。

    スニファ メカニズムの出力

    スニファ メカニズムは出力を JRun サーバーのログ ファイルに書き込みます。次の例はスニファ メカニズムの出力を示しています。この例では、クライアントは次の URL を使用して SnoopServlet を要求します。

    http://localhost:8101/servlet/SnoopServlet 
    

    JRun ログ ファイルに書き込まれる情報には次の行が含まれます。

    03/20 11:58:21 info HTTP Sniffer:Listening on port 8101, target is 
    localhost:80
    
    03/20 11:58:38 info SnoopServlet:init 
    03/20 11:58:50 info HTTP Sniffer:Accepted request 1
    03/20 11:58:50 info HTTP Sniffer:Header 1 --> GET /servlet/SnoopServlet 
    HTTP/1.0
    03/20 11:58:50 info HTTP Sniffer:Header 1 --> Connection:Keep-Alive
    03/20 11:58:50 info HTTP Sniffer:Header 1 --> User-Agent:Mozilla/4.7 
    (WinNT; I)
    03/20 11:58:50 info HTTP Sniffer:Header 1 --> Host:localhost:8101
    03/20 11:58:50 info HTTP Sniffer:Header 1 --> Accept:image/gif, image/
    x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    03/20 11:58:50 info HTTP Sniffer:Header 1 --> Accept-Encoding:gzip
    03/20 11:58:50 info HTTP Sniffer:Header 1 --> Accept-Language:en
    03/20 11:58:50 info HTTP Sniffer:Header 1 --> 
    Accept-Charset:iso-8859-1,*,utf-8
    03/20 11:58:50 info HTTP Sniffer:Header 1 --> 
    03/20 11:58:51 info HTTP Sniffer:Header 1 <-- HTTP/1.0 200 OK
    03/20 11:58:51 info HTTP Sniffer:Header 1 <-- Server:JRun Web Server/
    3.0
    03/20 11:58:51 info HTTP Sniffer:Header 1 <-- Date:Mon, 20 Mar 2000 
    16:58:51 GMT
    03/20 11:58:51 info HTTP Sniffer:Header 1 <-- 
    Set-Cookie:jsessionid=953571530946269859;path=/
    03/20 11:58:51 info HTTP Sniffer:Header 1 <-- Expires:Thu, 01 Dec 1994 
    16:00:00 GMT
    03/20 11:58:51 info HTTP Sniffer:Header 1 <-- Connection:Close
    03/20 11:58:51 info HTTP Sniffer:Header 1 <-- 
    Cache-Control:no-cache="set-cookie,set-cookie2"
    03/20 11:58:51 info HTTP Sniffer:Header 1 <-- Content-Type:text/html
    03/20 11:58:51 info HTTP Sniffer:Header 1 <-- 
    03/20 11:58:51 info HTTP Sniffer:Content 1 <-- 00000000 30 4C 59 42 41 
    32 0D 0A 30 4C 49 45 48 32 30 59   <HTML>..<HEAD><T
    03/20 11:58:51 info HTTP Sniffer:Content 1 <-- 00000016 4D 59 41 49 32 
    58 65 66 66 77 58 6B 79 7D 63 6B   ITLE>SnoopServle 
    ...
    

    この出力では、スニファ メカニズムがポート 8101 で要求を受信し、ポート 80 にその要求を転送しているのがわかります。

    スニファ メカニズムは、SnoopSerlvet に対する要求を検出すると、その要求と要求に含まれるすべてのヘッダ情報をログに記録します。要求に対応するログ ファイルの行には、右向矢印 (-->) が含まれています。

    Web サーバーからの応答には、ヘッダおよび要求のコンテンツが含まれています。応答に対応するログ ファイルの行には、左向矢印 (<--) が含まれています。応答では、応答のコードと ASCII テキストの両方がログ ファイルに含まれています。

    スニファ メカニズムのプロパティ

    次のプロパティを使用して、スニファ メカニズムの制御と設定を行います。

    sniffer.class

    スニファ メカニズムを定義する JRun クラスを指定します。既定では、このプロパ ティは allaire.jrun.http.Sniffer に設定されます。

    sniffer.port

    スニファ メカニズムが HTTP 要求を監視するポート番号を指定します。既定の ポート番号は 8101 です。

    スニファ メカニズムとスニファ メカニズムに関連する Web サーバーは、異なる ポート番号を使用する必要があります。したがって、プロパティ sniffer.portsniffer.target.port には、異なる値を指定する必要があります。

    sniffer.loglevel

    ログ ファイルへのスニファ出力のログ イベント タイプを指定します。指定できる 値は、debugerrorwarning、および info です。既定値は info です。

    JRun ログ メカニズムは、メッセージのレベルに基づいてメッセージをフィルタ 選択できます。詳細については、第 38 章 を参照してください。

    sniffer.logcontent

    true に設定すると、HTTP 要求/応答のメッセージのコンテンツをログに記録する ことを指定します。false に設定すると、スニファ メカニズムは要求/応答ヘッダ のみをログに記録します。メッセージのコンテンツはログに記録されませんが、 クライアントに転送されます。

    既定値は true です。

    sniffer.target.host

    クライアント要求を処理する Web サーバーのホスト名を指定します。既定値は、 localhost です。

    sniffer.target.port

    sniffer.target.host によって指定された Web サーバーが、スニファ メカニズム から転送された要求を受信するポート番号を指定します。スニファ メカニズムは、 sniffer.port によって指定されたポートで要求を認識し、Web サーバーが処理で きるように要求をこのポートに転送します。

    既定のポート番号は 80 です。

    スニファ メカニズムとスニファ メカニズムに関連付けられている Web サー バーは、異なるポート番号を使用する必要があります。したがって、プロパティ sniffer.portsniffer.target.port には、異なる値を指定する必要があります。

    sniffer.loggername

    スニファの出力メッセージを受信するために使用するロガーの名前を任意で指定 します。既定では、スニファ出力は、JRun サーバーのログ ファイルに書き込まれ ます。

    このプロパティを使用して、スニファ出力を受信するための独自のロガーを作成 できます。たとえば、ロガーを使用して、スニファ出力を独自のファイルに書き 込むことができます。ログ収集機能とロガーの詳細については、第 38 章を参照 してください。

    追加デバッグ リンク

    デバッグに関する多くの追加情報およびリンクを参照のために利用できます。次の表で、役立つリンクをいくつか紹介します。
    URL
    説明
    http://www.unix.hp.com/java/hpjmeter/index.html
    データのプロファイリングをグラフィカルに表示することで、パフォーマンスのボトルネックを検出できる、プラットフォームに依存しないツール
    http://developer.java.sun.com/developer/
    onlineTraining/Programming/JDCBook/perfTech.html

    Sun が提供するパフォーマンスの調整および分析に関するヒント
    http://developer.java.sun.com/developer/
    technicalArticles/Programming/Stacktrace/index.html

    Sun が提供する、Java スタック トレースの紹介
    http://www-4.ibm.com/software/os/warp/
    performance/javatip.htm

    IBM が提供する、Java パフォーマンスの調整に関する情報
    http://www-4.ibm.com/software/developer/
    library/tip-heap-size.html

    ヒープ サイズの管理および最適化に関する情報
    http://www-4.ibm.com/software/developer/
    library/java2/index.html

    IBM が提供する、Java、スレッド、および Linux でのスケジューリングに関する情報
    http://www-4.ibm.com/software/developer/
    library/perf-checklist/index.html

    IBM AIX サーバーに関する Java パフォーマンスの問題の検出と修正
    http://www-4.ibm.com/software/developer/
    library/jinsight/index.html

    Java プログラムの実行を視覚化するフリー ツール、Jinsight に関する情報
    http://www.research.ibm.com/journal/sj/391/
    viswanathan.html

    Java Virtual Machine Profiler Interface に関する情報
    http://java.sun.com/people/billf/heap/
    -Xhprof ファイルを読み取るための Java Heap
    Analysis Tool (HAT) に関する情報