カーネル デバッガーを使用したカーネル モード メモリ リークの検出

カーネル デバッガーは、カーネル モード メモリ リークの正確な場所を特定します。

プールのタグ付けを有効にする

先に GFlags を使用して、プールのタグ付けを有効にする必要があります。 GFlags は Windows 用デバッグ ツールに含まれています。 GFlags を起動し、[システム レジストリ] タブを選択し、[プールのタグ付けを有効にする] チェック ボックスをオンにして、[適用] を選択します。 この設定を有効にするには、Windows を再起動する必要があります。

Windows Server 2003 以降のバージョンの Windows では、プールのタグ付けは常に有効になっています。

リークのプール タグの特定

どのプール タグがリークに関連しているかを特定するには、通常、このステップで PoolMon ツールを使用するのが最も簡単です。 詳細については、「PoolMon を使用したカーネル モード メモリ リークの検出」を参照してください。

または、カーネルデバッガーを使用して、大量のプール割り当てに関連するタグを検索することもできます。 そのためには、以下の手順に従います。

  1. .reload (モジュールの再読み込み) コマンドを使用して、すべてのモジュールを再読み込みします。

  2. !poolused 拡張機能を使用します。 ページ メモリ使用量に基づいて出力を並べ替えるには、フラグ「4」を含めます。

    kd> !poolused 4 
    Sorting by Paged Pool Consumed
    
    Pool Used:
                NonPaged            Paged     
    Tag    Allocs     Used    Allocs     Used 
    Abc         0        0     36405 33930272 
    Tron        0        0       552  7863232 
    IoN7        0        0     10939   998432 
    Gla5        1      128      2222   924352 
    Ggb         0        0        22   828384 
    
  3. どのプール タグがメモリの最大使用量に関連しているかを特定します。 この例では、タグ「Abc」を使用するドライバーが最も多くのメモリ (約 34 MB) を使用しています。 したがって、メモリ リークはこのドライバーにある可能性が最も高そうです。

リークの検出

リークに関連するプール タグを特定したら、以下の手順に従ってリーク自体を特定します。

  1. ed (値の入力) コマンドを使用して、グローバル システム変数 PoolHitTag の値を変更します。 このグローバル変数は、その値に一致するプール タグが使用されるたびにデバッガーが中断する原因となります。

  2. PoolHitTag を、メモリ リークの原因と疑われるタグに設定します。 シンボル解決を速めるために、モジュール名「nt」を指定する必要があります。 タグ値はリトルエンディアン形式 (つまり、逆方向) で入力する必要があります。 プールタグは常に 4 文字であるため、このタグは実際には A-b-c-space であり、単に A-b-c ではありません。 そのため、次のコマンドを使用します。

    kd> ed nt!poolhittag ' cbA' 
    
  3. PoolHitTag の現在の値を確認するには、db (メモリの表示) コマンドを使用します。

    kd> db nt!poolhittag L4 
    820f2ba4  41 62 63 20           Abc  
    
  4. プールが Abc タグで割り当てられるか解放されるたびに、デバッガーは中断します。 これらの割り当てまたは解放操作のいずれかでデバッガーが中断するたびに、kb (スタック バックトレースの表示) デバッガー コマンドを使用してスタック トレースを表示します。

この手順を使用して、メモリ内のどのコードが Abc タグでプールを過剰に割り当てているかを特定できます。

ブレークポイントをクリアするには、PoolHitTag をゼロに設定します。

kd> ed nt!poolhittag 0 

このタグの付いたメモリが割り当てられている場所が複数あり、それらが自分で作成したアプリケーションまたはドライバー内にある場合は、これらの割り当てのそれぞれに固有のタグを使用するように、ソース コードを変更できます。

プログラムを再コンパイルできないが、コード内の考えられる複数の場所のどれがリークの原因となっているかを特定する場合は、各場所でコードをアンアセンブルし、デバッガーを使用してメモリに常駐するこのコードを編集して、各インスタンスが異なる (以前に使用されていない) プール タグを使用するようにします。 その後、システムを数分間、実行状態にします。 しばらく時間が経過したら、再びデバッガーで中断し、!poolfind 拡張機能を使用して、新しいタグのそれぞれに関連付けられたすべてのプール割り当てを見つけます。