アプリケーションのデバッグについて

 デバッグとは、アプリケーション内にあるバグ(機能不全や想定しない動作の原因)を特定し、修正する作業です。
 吉里吉里はいくつかのデバッグ支援機能を持っていますので、その機能を用い、アプリケーションをデバッグします。その方法について説明します。

デバッグ支援ウィンドウ

吉里吉里はデバッグを支援するためのウィンドウをいくつか提供しています。詳しくは各リンクの説明を参照してください。
コントローラ
各デバッグ支援ウィンドウを開いたり、イベント発生の停止や TJS コンテキストのダンプ、メッセージマップファイルの作成、システムの強制終了をすることができます。
スクリプトエディタ
簡単な TJS スクリプトの編集とその実行をすることができます。また、例外が発生したとき、その例外の発生位置を指し示すために「スクリプトエディタ (例外通知)」というスクリプトエディタのウィンドウが開く場合があります。
監視式
多くの式の結果を一度に確認することができます。
コンソール
吉里吉里のシステムや、ユーザスクリプトが出力する様々なデバッグ用メッセージを表示することができます。また、TJS2 式を入力してその場で実行し、式の結果を表示させる事もできます。

 特にコンソールでは、Debug.message によってユーザプログラムがプログラム中で出力したメッセージが表示されます。プログラムの任意の場所でメソッドを呼び出し、変数の内容をコンソールに表示させ、実行中の変数の内容を見ることができます。
 また、コンソールの下部の入力欄にTJS2式を入力し、Enterキーを押すことでその式をその場で実行することができます。これは、実行中のオブジェクトのメソッドを直接呼び出したり、オブジェクトのプロパティや変数に値を代入する際に便利です。
 コンソールへメッセージを表示する方法やログをファイルに記述する方法については、コマンドラインオプション の 「デバッグ関連のオプション」や Debug クラス を参照してください。

デバッグモード

 コマンドラインオプション で '-debug' を指定する (「デバッグモード」を'有効'にする) と、吉里吉里をデバッグモードで動作させることができます。
 デバッグモードではTJS2の動作は低速になりますが、デバッグに便利ないくつかの機能が有効になります。

型情報追跡機能
 TJS2のオブジェクトに関する情報が強化されます。
 デバッグモードではない場合は、たとえば KAG で kag.saveSystemVariables の情報を得ようとしてコンソールに kag.saveSystemVariables と入力しても
コンソール : kag.saveSystemVariables = (object)(object 0x0279E130:0x01EB0BD4)
 と表示されるだけですが、デバッグモードが有効の場合は
コンソール : kag.saveSystemVariables = (object)(object 0x0279E130[(function) KAGWindow.saveSystemVariables]:0x01EB0BD4[instance of class KAGWindow])
 のように型の情報が表示されます (':' で区切られた2つの部分のうち、前の部分はオブジェクトの型、後ろの部分はそのオブジェクトが動作するコンテキストです )。
 この機能は、コンソールで値を表示させる場合にとどまらず、(現バージョンでは)オブジェクトが文字列に変換される過程すべてで有効になります。
オブジェクトリーク検出機能
 削除されていない(解放されていない)オブジェクトを終了時に警告する機能が有効になります。
 TJS2は本来、ガベージコレクション機能により、作成されたオブジェクトは自動的に削除され、明示的な削除の指示は必要ありません。しかし、プラグインや吉里吉里本体のバグ、循環参照が原因で、オブジェクトが削除されないままになる(リークする)可能性があります。
 デバッグモードでは、終了時になってもまだ解放されていないオブジェクトがコンソールのログファイルに書き出されます。
 たった一個のオブジェクトが解放されなかっただけでも、そのオブジェクトに関連するオブジェクトが全て検出されるため、ログファイルが巨大になる可能性がありますので注意してください。

 System.exit メソッドは、アプリケーションを強制終了に近い形で終了させるもので、このメソッドでアプリケーションを終了させると多くのオブジェクトがリークし、大量のログが記録されますので注意してください。

Note
循環参照とは、A は B を参照している、B は A を参照しているという状況の事です。
たとえば、以下のスクリプトは循環参照を生成します。
var a = %[], b = %[];
a.b = b; b.a = a;

このような状況では、オブジェクト a は b を必要とし、オブジェクト b は a を必要としています。TJS2が採用しているガベージコレクションの方法(参照カウンタ)はこのような状況を検出してオブジェクトを解放するのは困難であるため、TJS2ではこのような状況を検出しません。そのため、いつまで経ってもこれらのオブジェクトが削除されることはありません (明示的に invalidate 演算子でどちらかのオブジェクトを無効化すると循環参照を断ち切ることができます)。

プラグインでは、参照カウンタの扱いを誤るとオブジェクトがリークする可能性があります。プラグインを作成して、その中でTJS2オブジェクトを扱う場合は、参照カウンタの扱いに十分注意してください。

削除中のオブジェクトでのスクリプト実行の警告
 オブジェクトは、削除あるいは無効化されるときに finalize メソッドが呼ばれます。
 オブジェクトが削除されるタイミングは、TJS2では「いつになるかわからない」ため、変なタイミングで finalize メソッドがよばれ、予期しない挙動を示す場合があります。デバッグモードでは、このような「不安定なタイミング」、つまり無効化されなかったオブジェクトがガベージコレクションによって削除され、finalizeメソッドが呼ばれたときに、警告がコンソールに表示されるようになります。
 警告は以下のような物です。

警告: anonymous@0x016DFA7C(9)[(function) finalize]: 削除中のオブジェクト 0x0167DD44[instance of class A] 上でコードが実行されています。このオブジェクトの作成時の呼び出し履歴は以下の通りです:
                     anonymous@0x016DFA7C(13)[(top level script) global]

 このような状況を防ぐため、new で作成したオブジェクトは、使用し終わったら明示的に invalidate 演算子で無効化することを推奨します。
 ただし、Array や Dictionary、Date のように finalize メソッドがない、あるいは finalize メソッドでは特に問題を起こすような動作を起こさないクラスのオブジェクトについては、明示的な無効化は必要ない場合があります。
 上記の警告は、明示的な無効化が無いままオブジェクトが削除されようとし、そのコンテキスト上でTJS2スクリプトが実行されようとした場合に表示されます。
呼び出し履歴の取得機能
 TJS2 の関数/メソッド呼び出し履歴をスクリプトから取得できるようになります。
 これには Scripts.getTraceString メソッドを用います。
 プログラムの途中に何か問題があり、そのメソッドがどこから呼ばれたのか分からない場合に、このメソッドを使って、呼び出し履歴をコンソールに出力したりができるようになります。