ハンドルリークの調査方法 ~ ハンドルリークとは?
この資料ではハンドルリークに関する調査方法についてお話したいと思います。
ハンドルリークとは?
開発者が Windows API を使ってカーネルオブジェクトを作成すると、Windows はカーネル内部にカーネルオブジェクトを作成し、 それを操作するための ハンドル を返します。開発者はこのハンドルを使って、カーネルオブジェクトを操作することができます。
言い換えると、Windows は開発者に対して、カーネルオブジェクトへのアクセスをハンドルを経由してのみ行わせることによって、 カーネルオブジェクトを保護しています。(このため、カーネルオブジェクトへのポインタを返さないのです)
例として、ファイルを扱う場合を考えてみましょう。
ファイルを操作するために、Windows では CreateFile などの API を用いてファイルを開きます。 「ファイルを開く」 というとき、Windows は 「ファイルタイプのカーネルオブジェクトを作成」 します。
そして プロセスハンドルテーブル に、ファイル・カーネルオブジェクトへのポインタ、そのオブジェクトへの参照カウント等を登録します。 ハンドルはプロセスハンドルテーブルのエントリのインデックスということができます。
同じカーネルオブジェクトが複数個所から使用されれば参照カウントが増え、逆にハンドルを閉じると参照カウントが減ります。
参照カウントがゼロになると、そのオブジェクト及びそれに関連するリソースが解放されます。
逆に閉じるのを忘れてしまうと、いつまでもリソースが残ります。この状態がハンドルリークです。 つまりハンドルリークとはハンドルの閉じ忘れにより、プロセス内に無駄なリソースが蓄積された状態になることです。
短時間しか実行されないプログラムならば、リーク系の不具合は表面に出てこない場合もあるかもしれません。 無駄なリソースが少しくらい蓄積したとしても、プログラム終了時に Windows が、割り当てられていたリソースを解放してくれるからです。
しかし IIS などのサーバー系のプログラムは 24x7 の稼動が求められていますから、プログラム終了時のクリーンアップに頼ることはできません。 少しのリークでも徐々に蓄積し、それがやがて問題を引き起こすことになります。この状況はハンドルのリークだけでなく、メモリリークなども同様です。
リークかどうかの判定
ハンドルの絶対数はタスクマネージャで簡単にわかります。しかしそのハンドルの数が多いからといって、 リークしているとは限りません。一時的にたくさんのハンドルを開いているだけで、後に閉じるかもしれないからです。
リークかどうか判断するためには、ある程度長期間に渡りハンドルの数を調べ、その数が徐々に増加し続ける傾向にあることを確認しなければなりません。
長期間の動向を調べるためには、パフォーマンスモニタのログが利用できます。Process パフォーマンスオブジェクトの Handle Count カウンターを使います。
ハンドルリーク箇所の特定
ハンドルリークが疑わしい場合、どうにかしてその 「閉じ忘れハンドル」 を特定し、 ちゃんと閉じるようにコードを変更しなければなりません。
どのようなハンドルが開かれているかは、 Process Explorer 等のツールでわかります。
これをパッとみただけで、 「あ!いけない!コードのあの部分が問題だ!」 とわかればそれに越したことはありません。
問題なのはそれでわからない場合です。どうしたらよいでしょうか。
具体的に調査するための方法があります。 次のページで具体的に説明しています。
!htrace デバッグコマンドを用いたハンドルリークのデバッグ方法 |