メモリ異常によるブルースクリーンの対処法

一、ブルースクリーン発生とダンプファイル
 ここのところ、原因不明のブルースクリーン(Blue Screen of Death: BSOD)の発生に悩まされている。当初、ブルースクリーンがFirefoxの使用中に起こり、そのバージョンが古いためにブルースクリーンが生ずることがあると言われていることから、Firefoxの更新で解決するのではと思った。暫くブルースクリーンが発生しなかったため、解決したかに思えたが、そうではなかった。

 ダンプファイルを調べてみる。minidumpファイルを表示するBlueScreenViewを見ると、ストップコードは
 0x19 BAD_POOL_HEADER
 0xC2 BAD_POOL_CALLER
 0x1A MEMORY_MANAGEMENT
 0x4E PFN_LIST_CORRUPT
 0xA  IRQL_NOT_LESS_OR_EQUAL
 となっている。

 BAD_POOL_HEADERとBAD_POOL_CALLERは、「カーネルプールマネージャが破損したプールヘッダあるいは不適切なプールの参照を検出」(『Windows Intermals, Sixth Edition, Part 2』、p.550)したことを示している。

 MEMORY_MANAGEMENTとPFN_LIST_CORRUPTは、「カーネルメモリマネージャがメモリマネージメントのデータ構成の破損あるいは不適切なメモリマネージメントのリクエスト(要求)を検出」(同上)したことを示している。

 IRQL_NOT_LESS_OR_EQUALは、「背後のページングファイルあるいはメモリにマップされたファイルにデータを保持するメモリ上のページフォールトがDPC(Deferred Procedure Call:遅延プロシージャコール)ないしディスパッチ(dispatch)のレベルと同じかそれより上のIRQL(Interrupt Reguest Level:割り込み要求レベル)で発生し、その要求によってメモリマネージャがI/O(入出力)処理が発生するのを待たなければならなくなったのだろう」ということを示している。「カーネルは、DPCないしディスパッチのレベル[優先度は「2」で下から3番目である;筆者注]と同じかそれより高いIRQLにおいては、待機することも、スレッドを再スケジュールすることもできない」のである(同書、p.549)。
 カーネルのIRQLについては、「カーネルやディバイスドライバを含むシステムの全てのコンポーネントは、IRQLをPassive level(Low levelとも呼ばれる)[優先度は「0」で最も低い;筆者注]に保つようにしている。ディバイスドライバが、そのIRQLが長期間不必要に上らないように保てば、適切な時点でハードウェアの割り込みに対応することができるから、そうしているのである」(同書Part 1、p.88)とされている。

 この場合、BlueScreenViewに"Caused By Driver"としていずれもntoskrnl.exeが挙っているが、メモリマネージャがntoskrnl.exe内に存在するからであって、ntoskrnl.exe自体に不具合があるわけではないことが多いようである。

 そこで、もう少し詳しくブルースクリーンの原因を探るためカーネルメモリダンプをWinDbg(Debugging Tools for Windows)["Debugging Tools for Windows (WinDbg, KD, CDB, NTSD)"]で開いてみる。

 そのデバッグの一部を抜き出すと、
******************************************************************************************
BAD_POOL_CALLER (c2)
The current thread is making a bad pool request. Typically this is at a bad IRQL level or double freeing the same allocation, etc.
Arguments:
Arg1: 0000000000000007, Attempt to free pool which was already freed
Arg2: 000000000000109b, (reserved)
Arg3: 000000000102040f, Memory contents of the pool block
Arg4: fffff8a0003888a0, Address of the block of pool being deallocated

Debugging Details:
------------------
POOL_ADDRESS: fffff8a0003888a0 Paged pool

FREED_POOL_TAG: CMNb

BUGCHECK_STR: 0xc2_7_CMNb

DEFAULT_BUCKET_ID: WIN7_DRIVER_FAULT

PROCESS_NAME: System

CURRENT_IRQL: 0

ANALYSIS_VERSION: 6.3.9600.17237 (debuggers(dbg).140716-0327) amd64fre

LAST_CONTROL_TRANSFER: from fffff800043b5be9 to fffff8000427e5c0

STACK_TEXT:
fffff880`04339a28 fffff800`043b5be9 : 00000000`000000c2 00000000`00000007 00000000`0000109b 00000000`0102040f : nt!KeBugCheckEx
fffff880`04339a30 fffff800`04563eff : fffff800`0448a700 fffff800`045627c0 fffff800`624e4d43 fffff800`044292d8 : nt!ExDeferredFreePool+0x1201
fffff880`04339ae0 fffff800`04562afe : fffff8a0`0016bde8 00000000`b918a805 fffff8a0`00f9a010 00000000`00000000 : nt!CmpFreeKeyControlBlock+0x123
fffff880`04339b10 fffff800`042881b5 : fffff800`044292d8 fffffa80`0cdbeb50 00000000`00000000 fffffa80`0cdbeb50 : nt!CmpDelayDerefKCBWorker+0x33e
fffff880`04339b70 fffff800`045178e2 : 00000000`00000000 fffffa80`0cdbeb50 00000000`00000080 fffffa80`0cd25b10 : nt!ExpWorkerThread+0x111
fffff880`04339c00 fffff800`0426ff46 : fffff880`04142180 fffffa80`0cdbeb50 fffff880`0414d1c0 00000000`00000000 : nt!PspSystemThreadStartup+0x5a
fffff880`04339c40 00000000`00000000 : fffff880`0433a000 fffff880`04334000 fffff880`043398a0 00000000`00000000 : nt!KxStartSystemThread+0x16

STACK_COMMAND: kb

FOLLOWUP_IP:
nt!CmpFreeKeyControlBlock+123
fffff800`04563eff e90effffff jmp nt!CmpFreeKeyControlBlock+0x36 (fffff800`04563e12)

SYMBOL_STACK_INDEX: 2

SYMBOL_NAME: nt!CmpFreeKeyControlBlock+123

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: nt

IMAGE_NAME: ntkrnlmp.exe
--以下略--
******************************************************************************************
 BAD_POOL_HEADER (19)
The pool is already corrupt at the time of the current request.
This may or may not be due to the caller.
The internal pool links must be walked to figure out a possible cause of
the problem, and then special pool applied to the suspect tags or the driver
verifier to a suspect driver.
Arguments:
Arg1: 0000000000000003, the pool freelist is corrupt.
Arg2: fffffa800cd1b100, the pool entry being checked.
Arg3: fffffa800cd1b100, the read back flink freelist value (should be the same as 2).
Arg4: fffff8800cd1b100, the read back blink freelist value (should be the same as 2).

Debugging Details:
------------------
BUGCHECK_STR: 0x19_3

DEFAULT_BUCKET_ID: WIN7_DRIVER_FAULT

PROCESS_NAME: lsass.exe

CURRENT_IRQL: 0

ANALYSIS_VERSION: 6.3.9600.17237 (debuggers(dbg).140716-0327) amd64fre

LAST_CONTROL_TRANSFER: from fffff800043f64b3 to fffff800042bf5c0

STACK_TEXT:
fffff880`0e56a708 fffff800`043f64b3 : 00000000`00000019 00000000`00000003 fffffa80`0cd1b100 fffffa80`0cd1b100 : nt!KeBugCheckEx
fffff880`0e56a710 fffff800`045b9bdf : fffffa80`00000003 fffffa80`0cd2dd08 fffffa80`1072ed90 00000000`00000000 : nt!ExDeferredFreePool+0xa53
fffff880`0e56a800 fffff800`045b99fb : fffffa80`00000000 fffffa80`0cdad700 00000000`00000050 fffff880`0e56a8a8 : nt!ObpAllocateObject+0x12f
fffff880`0e56a870 fffff800`04586894 : fffff880`0e56aa20 00000000`00000002 fffff8a0`0390f8f0 fffff8a0`01b9c060 : nt!ObCreateObject+0xdb
fffff880`0e56a8e0 fffff800`045925da : 00000000`00000000 00000000`01f4e938 00000000`00000001 fffffa80`0d414060 : nt!SepDuplicateToken+0xf4
fffff880`0e56a980 fffff800`0459284d : fffffa80`0d414060 fffff880`0000000a 00000000`00000001 00000000`00000001 : nt!NtOpenThreadTokenEx+0x33a
fffff880`0e56aaa0 fffff800`042be853 : fffffa80`0d414060 00000000`00000001 00000000`00000000 fffffa80`0d2e32a0 : nt!NtOpenThreadToken+0x11
fffff880`0e56aae0 00000000`77c4dbfa : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x13
00000000`01f4e8f8 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : 0x77c4dbfa

STACK_COMMAND: kb

FOLLOWUP_IP:
nt!ExDeferredFreePool+a53
fffff800`043f64b3 cc int 3

SYMBOL_STACK_INDEX: 1

SYMBOL_NAME: nt!ExDeferredFreePool+a53

FOLLOWUP_NAME: Pool_corruption

IMAGE_NAME: Pool_Corruption
--以下略--
******************************************************************************************
MEMORY_MANAGEMENT (1a)
# Any other values for parameter 1 must be individually examined.
Arguments:
Arg1: 0000000000041201, The subtype of the bugcheck.
Arg2: fffff680009fc890
Arg3: 91800001b1e67867
Arg4: fffffa8011cf0600

Debugging Details:
------------------
PEB is paged out (Peb.Ldr = 000007ff`fffdf018). Type ".hh dbgerr001" for details

BUGCHECK_STR: 0x1a_41201

DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT

PROCESS_NAME: nvxdsync.exe

CURRENT_IRQL: 0

LAST_CONTROL_TRANSFER: from fffff8000432e69e to fffff800042d2200

STACK_TEXT:
fffff880`0c406878 fffff800`0432e69e : 00000000`0000001a 00000000`00041201 fffff680`009fc890 91800001`b1e67867 : nt!KeBugCheckEx
fffff880`0c406880 fffff800`0429c691 : fffff880`0c406901 fffffa80`11a67b50 00000000`00000000 91800001`b1e67867 : nt! ?? ::FNODOBFM::`string'+0x13702
fffff880`0c4068c0 fffff800`0429c32a : fffffa80`11cf0600 fffffa80`17202b10 fffffa80`17202b10 00000001`3f912000 : nt!MiQueryAddressState+0x2b1
fffff880`0c406910 fffff800`045ac624 : fffff880`00000004 00000001`3f913000 fffffa80`11cf0600 fffff800`00000000 : nt!MiQueryAddressSpan+0xaa
fffff880`0c406980 fffff800`042d1493 : 00000000`00000d88 fffffa80`11a67b50 fffffa80`11a67b50 00000000`186bda58 : nt!NtQueryVirtualMemory+0x382
fffff880`0c406a70 00000000`76eddbea : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x13
00000000`186bda38 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : 0x76eddbea

STACK_COMMAND: kb

FOLLOWUP_IP:
nt! ?? ::FNODOBFM::`string'+13702
fffff800`0432e69e cc int 3

SYMBOL_STACK_INDEX: 1

SYMBOL_NAME: nt! ?? ::FNODOBFM::`string'+13702

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: nt

IMAGE_NAME: ntkrnlmp.exe
--以下略--
******************************************************************************************
 等々。

 ブルースクリーンに陥った時の状況がまちまちで、メモリマネージメントに関連して問題が発生しているようだが、その箇所は特定できない。

 参考までにPC環境を簡単に示すと、
 M/B : ASRock X79 Extreme6
 CPU : Intel Core i7 3930K
 RAM : Corsair 4GB X 4
 SSD : PLEXTOR PX-256M5Pro
 HDD : Western Digital 1GB X 2、2GB X 2、4GB、etc.
 Graphics : NVIDIA GeForce GTX 660
 OS : Windows 7 Professional SP1 x64

 因みに、Windows 7の場合は、デフォルトでは、「コントロールパネル」⇒「システム」⇒「システムの詳細設定」⇒「起動と回復」の「設定」をクリックすると表示される「システムエラー」の「デバッグ情報の書き込み」には、「最小メモリダンプ」と「カーネルメモリダンプ」しか選択できないことになっているようである。

 従って、「完全メモリダンプ」(Complete Memory Dump)に設定するには、レジストリとPageFile(仮想メモリ)のサイズを変更する必要がある。

 TechNet Blogsの「メモリ ダンプ ファイルを生成する方法について」等によると次の通りである。

○ 手動で以下のレジストリのサブキー配下のCrashDumpEnabledのレジストリエントリ(「値のデータ」)を「1」に設定する。

 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CrashControl

 その値の意味は、
 0=メモリダンプなし
 1=完全メモリダンプ
 2=カーネルメモリダンプ
 3=最小メモリダンプ
 となっている。

○ PageFile(仮想メモリ)の初期サイズと最大サイズを、物理メモリのサイズ+300MB以上に設定する。

 「コントロールパネル」から「システムの詳細設定」に至り、「パフォーマンス」の「設定」⇒「詳細設定」⇒「仮想メモリ」の「変更」をクリックして「仮想メモリ」のダイアログボックスを開く。「カスタムサイズ」を選択し、例えば物理メモリが16,384MBであれば、初期サイズ・最大サイズともに16,684MBと入力し、「OK」をクリックして再起動する。

 300MBを上乗せする理由は、「300 MByte はダンプ ファイルのヘッダー情報や二次ダンプ ファイルのために使われる領域です。現在サポートしているどの OS のどの環境にでも対応できるように余裕を持たせた値となっております」(上記TechNetのブログ)とのことである。

 完全メモリダンプファイルはWinDbgで開くと、"Kernel Complete Dump File"と表記され、カーネルメモリダンプファイルは、"Kernel Summary Dump File"と表記される。

 なお、完全メモリダンプの場合、当然ながら搭載メモリによってはダンプファイルのサイズは相当な量となるので注意を要する。

二、メモリ消費の急激な増加
 どうしたものかと思案しているとき、メモリの状態を常時表示するガジェットが普段と異なる振る舞いを示していることにふと気が付いた。PC起動後数分経つと、突如として使用中(Active)のメモリが急激に増大するのである。本機の場合、通常、起動後安定したアイドル状態であれば、2.2~2.5GB程度であるはずの使用メモリが、起動6、7分後には6GB台にまで急増している(図-1)。

 図-1
 MP01-Memory-Surge

 RAMMap(「SuperfetchとPrefetchについて~(2)」参照)でその変化を見てみると、PC起動直後は246MB程度であるPaged Pool(ページプール)が(図-2)、起動後6分ほど経過すると約4GBに急増し(図-3)、暫くするとPaged PoolのActiveであったもののうち約1.7GBがStandbyに、約2.1GBがModified(変更済み)となり、Activeは約314MBとなる(図-4)。その後は、Modified Pageは、少しずつディスクに書き出されるのであろうか、微減するものの、ほぼこの状態が長時間に渡って続くことになる。

 図-2
 MP02-RamMap1

 図-3
 MP03-RamMap2

 図-4
 MP04-RamMap3

 ところで、そもそもPaged Poolとは何か、確認し直してみる。『Windows Internals, Sixth Edition』の中を拾い読みする。

 同書Part 2のChapter 10、"Memory Management"の"Kernel-Mode Heaps (System Memory Pools)"には以下のように説明されている。

 「システムの初期化において、メモリマネージャは動的にサイズが定められた2つのプール(pools)あるいはヒープ(heaps)を生成する。それは、カーネルモードコンポーネントがシステムメモリに割り当てるために使用するものである。

 非ページプール(Non-paged pool)
 これは、常に物理メモリ内に存在することが保証されたシステムの仮想アドレスの領域から成り、それ故にページフォールトを招くことなくいつでもアクセスすることができる。従って、それはどの割り込み要求レベル(Interrupt Reguest Level: IRQL)からもアクセス可能である。なぜ非ページプールが必要かといえば、ページフォールトは、DPCないしディスパッチの割り込み要求レベル以上では要求を充たすことができないからである。従って、DPCないしディスパッチのレベル以上で実行され、あるいはアクセスされるであろういかなるコードやデータもページングされないメモリ内になければならないのである。

 ページプール(Paged Pool)
 これは、システムへあるいはシステムからページングされうるシステム空間内の仮想メモリの領域である。DPCないしディスパッチの割り込み要求レベル以上からメモリにアクセスする必要のないディバイスドライバがページプールを使用するのである。それはどのプロセスのコンテクストからもアクセス可能である。

 これら2つのメモリプールはどちらも、アドレス空間のシステム領域に位置し、全てのプロセスの仮想アドレス空間にマップされる。」(pp.212-213)

 また、メモリリーク(Memory Leak)とは、「プログラミングにおけるバグの一種。プログラムが確保したメモリの一部、または全部を解放するのを忘れ、確保したままになってしまうことを言う」(「メモリリーク」、Wikipedia)とされる。つまり、もはやプログラム上必要がないもかかわらず、メモリ領域が確保されたままでメモリの資源が無駄となっている状態を、メモリが漏れているという表現から、メモリリークと呼ぶようになったらしい。
 そのような状態が続くと、前述のようなブルースクリーンに至る不適切な事態が発生することにもなるのであろう。

 おそらく、我が機の状況は、メモリリークが発生しているということになろうか。

三、一般的な対処法
 ともかくも対処しなければならない。

● 先ずは、改めてMemtest86+でメモリ自体を検査してみるが、問題はない。

● 次に、とかく問題を起こしやすいとされるグラフィックス(ビデオ)ドライバを最新版に更新してみるも、変化は見られない。以前の古いバージョンにしてもみたが、同じである。

● WinDbgに挙っていたモジュール等を、BSODが起こる前の安定していた時期のバックアップから取り出し、入れ替えてみた。しかし、改善しない。

 こうなれば、手当たり次第である。
● ネットワークアダプタ(NIC: Network Interface Controller/Card)のドライバの更新や、UEFIやSSDのファームウェアの更新なども試みたが、効果なしである。

● 無駄だと知りつつシステム用のSSDをPLEXTORのPX-256M5ProからPX-256M6Proに換装したが、やはり無関係であった。

 一体、何が原因なのか。勿論、バックアップは保存してあるので、ブルースクリーンを起こしていない安定していた時期のOSに戻すことは可能である。それが1、2週間前のOSに戻すのであれば、一も二もなく復元するところである。しかし、どうもブルースクリーンを起こさない安全なOSのバックアップは、半年ないし1年前まで遡る必要があるようである。となると、それ以降現在までにインストールしたソフトの再インストールやシステムに加えた種々の変更等を再び行わなければならず、何とも気が進まない。それは最終手段であって、できれば現行のシステムの修復で乗り切りたい。まだやれることはあるはずである。

四、改めて原因の特定
 改めて、Driver Verifier、Process Explorer、Process Monitor、Poolmon(Memory Pool Monitor)等を使って調べてみることにした(「Windows の限界に挑む: ページ プールと非ページ プール」参照)。

1. 原因特定ツール
 先ず、これらユーティリティの使い方を簡単に見ておく。

● Driver Verifierは文字通りドライバを検証するツールである。これは、Windowsに組み込まれているので、直ぐに使用することができる。しかし、検証の結果を見るには、WinDbgをインストールしたもう1台のPCが必要である。つまり、ドライバを検証するには、ユーザモードデバッグではなくカーネルモードデバッグを行う必要があり、そのためには別のPCからデバッグを実行しなければならないと言うのである。

 カーネルデバッグ接続については、MSDN Libraryの"Setting Up Kernel-Mode Debugging Manually"、MSDN Blogsの「ネットワークケーブルを用いたカーネルデバッグ接続の設定手順」、「カーネルデバッガーを利用する [WinVista]」等に詳しく、詳細はそちらを御覧頂くとして、ここでは簡単な説明に留める。

 検証の対象となるPCをターゲットPCとし、カーネルデバッグを行うPCをホストPCとして、ホストPCにはWinDbgをインストールしておく。そして、両PCをデバッグケーブルで接続しなければならない。問題なのは、その接続ケーブルである。

 カーネルデバッグ接続に使用できるケーブルは、OS等によって制約があると言う。

○ ネットワーク(イーサネット)ケーブルが使えるのは、ターゲットPCのOSがWindows 8以降で、ホストPCのOSはWindows XP以降でなければならない。

○ USB 2.0ケーブルが使えるのは、ターゲットPCのOSがWindows VISTA以降で、ホストPCのOSはWindows 2000以降である。但し、そのUSBケーブルは、USB2 Debug Device Functional Specificationの要件を充たすデバッグ専用のケーブルでなければならず、容易に入手することができないのが現状である。

○ USB 3.0ケーブルの場合は、ターゲットPCとホストPCがUSB3.0に対応したポートを装備し、そのターゲットPCのUSBポートはデバッグをサポートしている必要がある。となると、OSについては、ターゲットPCがWindows 8以降、ホストPCはWindows 7以降でなければならないようである(「Windows8時代のKernel Debugging USB 3.0編」参照)。このケーブルは、USB1.1/2.0互換用のストレート結線も電源線(Vbus)も含まないA-Aタイプのクロスオーバーケーブルでなければならないとのこと。
 このUSB3.0専用のデバッグケーブルは、今のところ海外製のものが入手可能である(DataPro社のUSB 3.0 Super-Speed A/A Debugging Cable等)。しかし、海外への注文となると、為替レートや送料によっては少し出費がかさむこともあるため、ケーブルを自作する匠もおられる(「USB 3.0 Kernel Debugging のための準備」)。

○ IEEE 1394ケーブルは、ターゲット・ホスト両PCのOSがWindows XP以降であれば使用できる。

○ シリアルケーブルは、どちらもWindows NT 4.0以降であればよいが、シリアルポートを備えているPCは最近ほとんど見かけない。

 私の場合、1394を使う機器を持っているため、自作機の全てには1394ポートを備えたマザーボードを使用しており、ターゲットPCはWin 7であるから、今回はIEEE 1394ケーブルを用いることにする。ホストPCはXP機を選択。

 ターゲットPCがWin 8以降であれば、ネットワークケーブル(LANケーブル)がカーネルデバッグ接続には便宜であろう。しかし、Win 7以前のOSを使用するPCで1394ポートを備えていないPCをターゲットにする場合は、残念ながらカーネルデバッグ接続は事実上不可能であろう。

 カーネルデバッグ接続の手順は以下の通りである。

① 先ず、ホストPCとターゲットPCを1394ケーブルで接続する。

② ホストPCでWinDbgを起動し、「File」メニューの「Kernel Debug」を選択する。現れた「Kernel Debugging」のダイアログボックスの「1394」のタブを開き、「Channel」にターゲットPCで指定する予定の数字、ここでは「1」を入力して、「OK」をクリックする。そのまま待機。

③ ターゲットPCでmsconfig.exe(システム構成)を起動し、「ブート」タブを開き、「詳細オプション」をクリックし、「デバッグ」にチェックを入れ、「デバッグポート」で「1394」を選び、「チャンネル」を他に使用していなければ「1」とし、「OK」をクリックして、再起動する。

 コマンドプロンプトを管理者権限で開き、
  bcdedit /debug on
  bcdedit /dbgsettings 1394 channel:1
 とそれぞれ入力してEnterを押下し、再起動することも可能である。

 それから、Driver Verifierを実施したい場合は、その設定をする。

 Driver Verifierの設定ないし使用方法については、「Driver Verifier によるメモリーリークのデバッグ方法について」や「Driver Verifier:ドライバーのトラブルシューティングに使えるツール」等に詳しく説明されているので、そちらを御覧頂きたい。

 今回の場合は、問題のあるドライバを見つけ出すことが主眼であるので、検索ボックスからverifier.exeを起動し、「タスクの選択」で「標準の設定を作成する」を選び、「検証するドライバーの選択」で「一覧からドライバーを選択する」から疑わしいと思われるドライバを選んでVerifierを実行することになる。

● Poolmon(Memory Pool Monitor)は、Nonpaged Pool(非ページプール)とPaged Pool(ページプール)の利用状況をモニターすることができるユーティリティであり、WDK(Windows Driver Kit)の中に含まれている。WDKをデフォルトのフォルダにインストールしていれば、C:\Program Files (x86)\Windows Kits\8.1\Tools\x64内にpoolmon.exeがあり、それを実行するだけである。コマンドプロンプト(管理者権限で)からも使用できる。("Troubleshooting Pool Leaks Part 2 - Poolmon"参照)

 各項目の頭文字のキーを打つと、その項目でソートできる。「t」のキーを打てば、Tagのアルファベット順に、「a」を打てば、Allocations、「b」を打てば、Bytesの数量の多い順に並び替えることができる。また、Nonpaged PoolとPaged Poolを分けて表示させるには、「p」のキーを押せばよい。

 但し、Pool内の領域が割り当てられるドライバは、それぞれに付されたTagで表示されているので、それを特定するには、コマンドプロンプトで
C:\Windows\System32\drivers>findstr /m /l xxxx *.sys
(xxxxに特定したいTag名を入れる)
と入力すればよいとのこと。詳細は、TechNet Blogsの「リソース不足について-第2回」を御覧下さい。

● Process Explorer(procexp.exe)Process Monitor(Procmon.exe)は、RAMMapと同じくSysinternalsが提供するWindows内部の詳細な状況を調べることのできるツールである。これらは、単一の実行ファイルであるため、ダウンロード後そのまま使えて便宜である。

2. 原因を割り出す
 怪しいと踏んだ幾つかのドライバについてverifier.exeを実行してみたが、残念ながら、不具合のあるドライバを見つけ出すことはできなかった。

 Poolmon.exeのTagをたよりに探ってもみたが、原因の特定には至らなかった。

 そこで、ページプールが増加する前に、Process Monitor(Procmon.exe)を起動させ、ページプールが急増した後にそれを保存し、そのProcess Monitorの記録をページプールの急増した時刻をたよりに調べていった。これを数回繰り返したところ、その時刻に必ずある一群のファイルにアクセスがなされていることが分かった。それらは、バックアップソフトのAcronis True Image Home 2012によって作成されたバックアップファイルである。1日に1回、シャットダウン時にバックアップを4TBのHDDに保存するようにスケジュールしているため、そのHDDには大量のバックアップファイルが保存されている。PC起動後一定の時間が経つと、図-5のように1つのファイルにつき11の一連の処理がなされて、それが同種のバックアップファイル全てに対して一気に行われ、それと同時にページプールが急激に増加するのである。

 図-5
 MP05-ProcessMonitor

 それらのファイルを作成したのはTrue Imageであるから、取り敢えず、True Imageが係わるサービス、Acronis Nonstop Backup ServiceとAcronis Sync Agent Serviceを停止ないし無効にしてみたが、これらのアクセスに変化は見られず、ページプールの増加も治まらない。

 True Imageの「起動時にバックアップを検索」という機能を無効にしてみるも、効果はない。

 一旦、True Imageをアンインストールしてみたが、改善しない。Acronis Clean Up Utilityを使ってTrue Imageを完全にアンインストールしたが、無駄であった。

 やはり、このプロセスは何か、知る必要がある。

 Process Nameにはsvchost.exeとある。svchost.exeは、Service Hosting Processという名前が示す通り、各種のサービスを親となって起動するためのプロセスである。調べつつ紐解いていくことにする。

 Process Monitorの記録を見ると、問題となる各スレッドのOperationには、IRP Major Function codeとfast I/O codeがある。ファイルシステムドライバ(File System Driver: FSD)やファイルシステムフィルタドライバ(File System Filter Driver)等に関する知識はほとんどなく、この機会にMSDN Libraryを巡って少しばかり調べてみた。

 "Filtering IRPs and Fast I/O"には、「file system filter driverは、1つ以上のファイルシステムやファイルシステムボリュームのためにI/O request(要求)にフィルタをかける。各I/O要求はIRP(I/O Request Packet:入出力要求パケット)又はfast I/O要求として現れる。IRPはドライバのIRP dispatch routineによってハンドルされるI/Oシステム構造体である。fast I/O要求はドライバのfast I/O callback routineによってハンドルされる。
 フィルタドライバが初期化されるとき、そのDriverEntry routineはそのフィルタドライバのIRP dispatch routineとfast I/O callback routineをレジスタに登録する。それらのroutineの1組だけを各フィルタドライバのためにレジスタに登録することができる。
 IRPの中には、fast I/Oと同等の性質を持つタイプもあり、fast I/O要求はIRPと同等の性質を持つものもある。しかし、IRPはfast I/Oがハンドルすることができない多くのタイプのI/Oをハンドルする。また、ある特殊なfast I/O routineは、IRPを生成することなく、キャッシュマネージャやメモリマネージャのためにファイルシステムのリソースをあらかじめ取得する目的で使用されることもある。このようにして、大部分の場合、IRPとfast I/O要求は、I/O処理の役割を分け合って行うのである。」と説明がある。

 また、"IRP Major Function Codes"では、「全てのIRPに対して各ドライバ固有のI/Oスタックロケーション (IO_STACK_LOCATION)は、major function code (IRP_MJ_XXX)を含んでおり、それがドライバ又はその配下のディバイスドライバがI/O要求を充たすために如何なるoperation(処理)を行うべきかをそのドライバに命じる。各カーネルモードドライバは、それがサポートしなければならないmajor function codeのためにdispatch routineを提供しなければならない。」と解説される。

 さらに、前述の一連の処理の冒頭にあるIRP_MJ_CREATEについては、「I/Oマネージャは、新たなファイルやディレクトリが作成されたとき、あるいは存在するファイル、ディバイス、ディレクトリ若しくはボリュームが開かれたときに、IRP_MJ_CREATEの要求を出す」("IRP_MJ_CREATE")と解説されている。

 そこには、「注意 レガシィフィルタドライバがcreate後のコールバックで再度createを発行した場合には、そのドライバは再解析ポイント(reparse point)に関連するバッファ(予備バッファ)を解放し、NULLにセットしなければならない。レガシィフィルタドライバがこのバッファを解放せず、NULLにセットしなければ、そのドライバはメモリをリークすることになる」との記載もある。

 本機がこの症状であるかどうかは判断しかねるが、この処理にメモリリークの危険性があることは分かった。Process Monitorを見ると、当然ながらこれに類似した処理は他にも多数存在するが、これらのバックアップファイルに対する一連の処理だけがメモリリークを引き起こしていることは間違いなかろう。

 各プロセスの冒頭のスレッドをダブルクリックして(あるいは右クリックから)プロパティを開くと、「Event」タブには「Desired Access Read Data/List Directory, Read Attributes」とある(図-6)。

 図-6
 MP06-ProcessMonitor-Event

 データや属性の読み取り等を目的としたこのようなアクセスが、PC起動後間もないアイドル時に、バックアップアプリケーションが作成したファイルに対して必要なのだろうかと思いつつ、Process Monitorの上記プロパティの「Process」タブを開くと、Command Lineには、「C:\Windows\system32\svchost.exe -k LocalSystemNetworkRestricted」とある(図-7)。

 図-7
 MP07-ProcessMonitor-Process

 前述したように様々なサービスの起動に係わるsvchost.exeであるが、『Windows Internals, Sixth Editon Part 1』のp.334の"Major Service Groupings"という表は、"LocalSystemNetworkRestricted"というサービスグループに含まれるサービスには、DWM (Desktop Window Manager), WDI (Windows Diagnostic Infrastructure) System Host, Network Connections, Distributed Link Tracking, Wired/WLAN AutoConfig, User-Mode Driver Framework Service, Superfetch, Portable Device Enumerator, Program Compatibility, Offline Files等々があると示している。

 この中のどのサービスが行われているのか。このプロパティの「Stack」タブを開くと、sysmain.dllが係わっていることが分かる(図-8)。

 図-8
 MP08-ProcessMonitor-Stack

 sysmain.dllは、Superfetchというサービスを行うときに使用されるダイナミックリンクライブラリである。従って、このプロセスは、Superfetchに係わる処理を行っていると判断できる。おそらく、Superfetchが、かつてTrue Imageが行ったアクセスをシナリオに記憶し、それに基づいてこれらの処理を行っているということなのであろうか。

3. 対処法を探る
 そこで、この症状が出る前に、Process Explorer(procexp.exe)を起動させ、マウスポインタを各svchost.exeの上に置いて行き、「Services: Superfetch [SysMain]」と表示されるsvchost.exeを確認して、その右クリックから「Suspend」を選択し、一時的にこのプロセスを停止して暫く様子を窺うことにする(図-9)。

 すると、バックアップファイルに対する一連のアクセスは起こらず、従って、ページプールの急増も発生しない。

 図-9
 MS09-ProcessExplorer-Suspend

 さて、問題はどう処置するかである。

 レジストリでSuperfetchとPrefetcherのいずれか一方だけを無効にしても駄目であり、両方とも無効にした場合だけ(「SuperfetchとPrefetchについて~(1)」参照)、この症状は治まる。ところが、有効にすると再び発生するのである。

 Superfetch・Prefetchにおいて、特定のファイルに対する読み取りだけが異常を引き起こしているのであるから、単にこのサービスを無効にしたからといって、真の解決にはならない。このサービスに不適切な振る舞いをさせている大元の原因が存在するはずであり、それを取り除かなければ、原状に復したとはいえない。そのような原因を内に抱えたままPCを使用することは、いずれ別の問題を生じさせる危険も孕んでいる。

 不思議なことに、Prefetchフォルダ内のファイルを全て削除しても、再発は防げないのである。

 一体全体、何をどうすればよいのか。

 webをさまよっているうちに、次のような記述も目にした。
「不正なアクセスや無効なページフォールトは、セグメンテーション違反やバスエラーを起こすことがあり、OS環境によっては、プログラムを強制終了(クラッシュ)させ、あるいはコアダンプを生じさせるおそれがある。これらの問題の多くは、ソフトウェアのバグによるものであるが、オーバークロックが原因で起こるようなハードウェアのメモリエラーがポインタを壊し、正常なソフトウェアに障害をもたらすこともある。」("Page fault"、Wikipedia

 試しに、CPUのオーバークロック(overclock:OC)を解除し、定格に戻してみたが、無駄であった。

 解決策を見出せずに懊悩しているさなか、不意にTrue ImageにはWindowsのVolume Shadow Copy Service(VSS)を使用してファイルを自動的にバックアップする機能があることを思い出した。AcronisのKnowledge Baseに、「Acronis True Image には、Microsoft VSS サービスを自動的に使用して、開かれたファイル/フォルダまたはデータベース(データベースが VSS テクノロジをサポートする場合)の一貫したバックアップを作成するための技術が搭載されています。」(「16978: Acronis True Imageを使用してVSSを搭載したシステムをバックアップする」)とある。

 もはやこれ以外に怪しい点は見当たらない。といっても、具体的にTrue Imageのこの機能とVSSとSysMainがどのような連関を持っているかは不明であったのだから、それは単に、ここらあたりに元凶が潜んでいるのではないかという漠然とした直観に過ぎなかったのだが。

 ファイルのシャドウコピーは、「コントロールパネル」⇒「システム」⇒「システムの詳細設定」⇒「システムの保護」と辿ると、ドライブ毎に設定可能である。ドライブを選択し、「構成」をクリックすると現れるダイアログボックスで「ファイルの以前のバージョンのコピー」を保存するか否かを設定する。この「ファイルの以前のバージョンのコピー」がファイルのシャドウコピーのことである。

 本機は、システムドライブだけ「システム設定とファイルの以前のバージョンを復元する」設定にしていた。試しに「削除」を行ってみたが、無駄であったので、「システムの保護を無効にする」を選び、Superfetch・Prefetchを無効にして、再起動をかけることにした。

 これが駄目なら1年前のシステムに戻すしかない。そう思い定め、念のためCPUの周波数は定格のまま行った。

 そうして、Superfetch・Prefetchを再び有効にしてみたところ、Paged Poolの急増は起こらない。PCをシャットダウンし、コールドブートしても起こらない。システムの保護やOCを以前の設定に戻し、改めてTrue Imageをインストールしても大丈夫である。Process Monitorで確認すると、PC起動後数時間経っても、上述のようなバックアップファイルへのアクセスは発生していない。ようやく、このメモリリークから解放されたのである。

五、まとめ
 Acronis製のTrue Image等のバックアップソフトを使用するWindows環境で、メモリリークが発生し、BSOD(ブルースクリーン)に悩まされている場合の解決策として、
 (1) Superfetch・Prefetchを無効にし、Prefetchフォルダ内の全てのファイルを削除すること、
 (2) 「システムの保護」を無効にすること、
 (3) OCを行っているならば、定格に戻すこと、
 (4) Acronis製品をアンインストールすること、
 これらのいくつかをあるいは全てを試してみてはいかがでしょうか。これらが不具合解消の契機となるやもしれない。

 勿論、True Image Home 2012にバグがあると即断することはできない。3年以上これを使ってきて、これまでにこのような問題は生じていなかったのであるから。しかし、このアプリケーションのある動作(おそらく「起動時にバックアップを検索」する動作と推察される)に様々な要因が重なってある種の不適切な処理が生じ、その影響によりVSSやSysMain等が何らかの不調を来たしたと考えられる。

 とすれば、この問題を起こすおそれのある疑わしい機能は可能な限り使わないに越したことはない。True Imageには「起動時にバックアップを検索」するという機能を持つバージョンがあり、デフォルトでこの設定項目にチェックが入っている場合があるので、後顧の憂いを残さないためにこのチェックを外しておくことが望ましいのではないかと考えている。現に、True Image 2015では、この機能は廃止されている(「48734: Acronis True Image 2015: 廃止された機能」)。

 Paragonのバックアップソフト(Hard Disk Manager等)の方が経験的にバックアップや復元は安定していると思われるが、バックアップのスケジュールに「シャットダウン時」の設定がないため、Acronisのものを主に使っているのである。

 なお、同様の症状でなくともブルースクリーン一般の原因の特定に拙文がお役に立てば幸いである。

 さらに一言。
 今回のトラブル解消の端緒を開いてくれたのは、他ならぬCPUやメモリ等のハードウェアの使用状況を常時表示してくれるガジェットである。これまでにも幾度となくこれらのガジェットには救われた(「水冷CPUクーラー交換」参照)。何度も申し上げてきたことだが(「ガジェットをなぜ見捨てる」、「Windows 10 Technical Previewを入れる」参照)、Microsoft社には、ガジェットの有用性を再認識し、ガジェットを復活して頂きたいと切に願う。

tag : Paged Pool Memory Leak Procmon procexp Verifier

コメントの投稿

管理者にだけ表示を許可する

Re: No title

ナヤンデルタール人さん、
コメント、ありがとうございます。

ドライバについては、やはりディバイスの製造元ないし販売元がWindows10対応版を提供してくれるのを待つということになるでしょうね。
Windows10対応のドライバに不具合があるのでしたら、製造元ないし販売元に情報を提供して改善を求めるしかないでしょうかね。

No title

v-16 すごい知識量で畏れ入ります!
このままコピーして参考書にさせていただきます。

 ぜひともWin10のディスクドライブのドライバー認識不可問題も解析して戴けたら。。。と密かに期待しております。
プロフィール

そんぷうし ふうえん

Author:そんぷうし ふうえん

忙中閑は、こっそりと見出す。
カミさんと子どもたちが寝静まるのを待って、夜な夜なPCの前に端座し、その不可思議なる箱の内奥にそっと手を入れては、悦に入る日々なのであります。
或るときは、ふらふらと知恵袋の回答者となって徘徊。
時としてその手はPC以外の内奥にも。


※ リンク貼付及び引用は自由ですが、引用する場合は該当ページのURL及びタイトルを明記して下さい。

Automatic Translation
If you click a language below on any page, the translator is supposed to display the latest page at first. So you need to jump back to the previous page you were about to read.
Please note that there are some translations that are non-grammatical and do not accurately reflect the meaning of the originals because of machine translation.
 【Translated by Google Translate】
全記事一覧表示

   全ての記事のタイトルを表示する

最新記事
カテゴリ別アーカイブ
最新コメント
月別アーカイブ
検索フォーム
リンク
最新トラックバック
RSSリンクの表示
累計閲覧回数
  
QRコード
QR