Windows の限界に挑む: USER オブジェクトと GDI オブジェクト – 第 2 部

翻訳元: Pushing the Limits of Windows: USER and GDI Objects – Part 2 (英語)

前回は、 2 つの主要なウィンドウ マネージャー リソースのうちの 1 つである USER オブジェクトの制限、およびこのオブジェクトの使用状況を測定する方法を取り上げました。今回は、もう 1つの主要なリソースである GDI オブジェクトを取り上げます。いつもと同様に、この記事を読む前に今までの記事をお読みになることをお勧めします。USER リソースと GDI リソースに関する制限には、今までの記事で取り上げた制限をベースとするものもあるからです。"Windows の限界に挑む" シリーズの他の記事の一覧を以下に示します。

GDI オブジェクト

GDI オブジェクト (英語) は、フォント、ビットマップ、ブラシ、ペン、デバイス コンテキスト (描画領域) などのグラフィックス デバイス インターフェイス リソースを表します。USER オブジェクトの場合と同様に、ウィンドウ マネージャーは、プロセスで作成できる GDI オブジェクトの数を最大 10,000 個に制限します。次のように、–g スイッチを指定して Testlimit を実行することでこれを確認することができます。

図 1

図 1

Process Explorer のプロセス プロパティ ダイアログの [Performance] ページで、個々のプロセスでの GDI オブジェクトの使用状況を確認することができます。また、Process Explorer に [GDI Objects] 列を追加すると、さまざまなプロセスでの GDI オブジェクトの使用状況を監視することができます (下図参照)。

図 2

図 2

また、USER オブジェクトと同様に、GDI オブジェクトには 16 ビットとの相互運用性のために 16 ビットの識別子が割り当てられるので、1 つのセッションで作成できる GDI オブジェクトの数は 65,535 個に制限されます。Windows Vista 64 ビット システムで Testlimit を実行してこの制限に達したときのデスクトップのようすを以下に示します。

図 3

図 3

[スタート] ボタンは本来の位置である画面左下にありますが、タスク バーの残りの部分は画面上部に表示されていることに注目してください。また、デスクトップは黒くなり、サイドバーの色はほとんどなくなっています。これと同じことが起こるとは限りませんが、通常と異なる動作が発生するようになり、信頼できる方法でデスクトップと対話することができなくなる可能性があることがわかるでしょう。[スタート] ボタンを押したときに画面がどのような表示に切り替わったかを以下に示します。

図 4

図 4

USER オブジェクトと違って、GDI オブジェクトはデスクトップ ヒープからは割り当てられません。Windows XP システム、およびターミナル サービスがインストールされていない Windows Server 2003 システムでは、GDI オブジェクトは一般的なページ プールから割り当てられ、他のすべてのシステムでは、セッションごとのセッション プールから割り当てられます。

カーネル デバッガーの "!vm 4" コマンドを使用すると、仮想メモリに関する一般的な情報がダンプされます。出力される情報の最後にはセッション情報も含まれています。次の図に示すように、Windows XP システムでは、セッション ページ プールが使用されていないことが示されます。

図 5

図 5

次の図に示すように、ターミナル サービスがインストールされていない Windows Server 2003 システムでも、出力は同様です。

図 6

図 6

したがって、以前の記事「Windows の限界に挑む: ページ プールと非ページ プール」で説明したように、このようなシステムにおける GDI オブジェクトのメモリ制限はページ プールの制限です。ただし、同じ Windows Server 2003 システムにターミナル サービスがインストールされている場合は、次の図でセッション プールの使用量がゼロになっていないことからわかるように、GDI オブジェクトはセッション プールから割り当てられます。

図 7

図 7

上の図に示した !vm 4 コマンドの出力ではセッション ページ プールの最大量とセッション プールのサイズも表示されていますが、Windows Vista 以上のバージョンのシステムでは、セッション ページ プールの最大量とセッション領域のサイズは可変なので表示されません。このようなシステムにおけるセッション ページ プールの使用量の上限は、セッション ページ プールに使用できるアドレス領域の最大量、または、システムのコミット制限です (この 2 つのうち小さい方が上限となります)。同じコマンドを Windows 7 システム上で実行した場合の出力を以下に示します。この出力では、現在のセッション ページ プール使用量がセッションごとに示されています。

図 8

図 8

ご想像のとおり、メインの対話セッションであるセッション 1 が最も多くのセッション ページ プールを消費しています。

"–g 0" スイッチを指定して Testlimit ツールを実行すると、GDI オブジェクトに使用される記憶域を使い果たすとどうなるかを確認することができます。–g の後に指定する数値は、Testlimit が割り当てる GDI ビットマップ オブジェクトのサイズですが、0 を指定すると、可能な限り最大のオブジェクトの割り当てが試行されます。32 ビットの Windows XP システムでの実行結果を以下に示します。

図 9

図 9

Windows XP、または、ターミナル サービスがインストールされていない Windows Server 2003 では、Windows Driver Kit (WDK) の Poolmon ユーティリティを使用して、GDI オブジェクトの割り当てをプール タグごとに確認することができます。Windows XP システムで Testlimit がページ プールを使い果たしているときの Poolmon の出力は、割り当てられるバイト数に基づいて並べ替えると次のようになりました (割り当てられるバイト数に基づいて並べ替えるには、Poolmon 画面で「b」と入力します)。この出力から、Windows XP でのビットマップ オブジェクト用のタグは Gh05 であることが推測されます。

図 10

図 10

ターミナル サービスがインストールされている Windows Server 2003 システム、および Windows Vista 以上のバージョンのシステムでは、確認するセッションを指定するために、/s スイッチを指定して Poolmon を実行する必要があります。ターミナル サービスがインストールされている Windows Server 2003 システムでの Testlimit の実行結果を以下に示します。

図 11

図 11

"poolmon /s1" というコマンドを実行すると、セッション 1 の中で最も割り当て量が大きいタグが示されます。次の図で Gh15 タグが一番上に表示されていることを確認でき、ビットマップの割り当てに異なるタグが使用されていることがわかります。

図 12

図 12

Windows XP システム上では Testlimit で約 58 MB のビットマップ データを割り当てることができましたが (この数値は、ビットマップ オブジェクトによる GDI の内部オーバーヘッドを表しているわけではありません)、Windows Server 2003 システム上では Testlimit で 10 MB のビットマップ データしか割り当てることができなかったことに注目してください。Windows Server 2003 システムの場合の方が数値が小さいのは、Windows Server 2003 ターミナル サーバー システムのセッション プールが 32 MB しかないためです。これは、Gh15 タグに割り当てられている量として Poolmon によって示されたメモリの量とほぼ同じです。"!vm 4" の出力は、セッション 1 用のセッション プールが使い果たされ、その後で試行されたセッション プールから GDI オブジェクトへの割り当てが失敗していることを示しています (下図参照)。

図 13

図 13

カーネル デバッガーの !poolused コマンドを使用してセッション プールの使用量を確認することもできます。まずは、適切なセッションに切り替えます。これを行うには、/p スイッチ、およびそのセッションに接続されているプロセス オブジェクトのアドレスを指定して、.process コマンドを実行します。特定のセッション内で実行されているプロセスを確認するには、!sprocess コマンドを使用します。同じ Windows Server 2003 システムでの !poolmon の出力を以下に示します。"c" オプションを指定して !poolused を実行しているため、出力は割り当てられたバイト数に基づいて並べ替えられています。

図 14

図 14

残念ながら、ウィンドウ マネージャーのヒープ タグと各タグが表すオブジェクトの間のマッピングは公開されていませんが、カーネル デバッガーの !poolused コマンドを実行すると、デバッガーのインストール ディレクトリ内にある triage.ini ファイルを使用して、タグに関する、より説明的な情報が出力されます。このコマンドの出力では、Gh15 は GDITAG_HMGR_SPRITE_TYPE であることが示されています。これは "Gh15" と比べて少しわかりやすいだけですが、他のタグに関して出力されている情報には、これよりわかりやすいものもあります。

さいわい、GDI オブジェクトや USER オブジェクトに関する問題のほとんどは、特定のプロセスで作成された GDI/USER オブジェクトの数が、1 つのプロセスで作成できる GDI/USER オブジェクトの数の上限である 10,000 個に達したことによるものなので、セッション プールを使い果たす原因となっているプロセスやページ プールを使い果たすまで GDI オブジェクトが割り当てられる原因となっているプロセスを特定するためのより高度な調査は不要です。

次回は、システム ページ テーブル エントリ (システム PTE) を取り上げます。これも、達する可能性のある制限を持つ主要なシステム リソースの 1 つです (Windows Server 2003 システムのリモート デスクトップ セッションでは特にその可能性があります)。

公開: 2010 年 3 月 31 日水曜日 10:03 PM 投稿者: markrussinovich (英語)

ページのトップへ

共有

ブログにコピー: ([Ctrl] + [C] でコピーしてください)