デスクトップ ヒープの枯渇

こんにちは。 Windows サポートの水上です。
今回は、よくあるお問い合わせのひとつである、デスクトップ ヒープの枯渇について、ご紹介します。

サーバーやデスクトップ PC を運用するにあたって、次のような事象が発生したことはないでしょうか。

  • 他のアプリケーションは正常に動いているのに、アプリケーションの起動やバッチ処理に失敗する。
  • イベント ID 243 や 244 が記録される。
  • 例外コード 0xc0000142 でイベント ID 1000 が記録される。

上記のような事象は、デスクトップ ヒープの枯渇により生じている可能性があります。
デスクトップ ヒープの上限サイズはレジストリで変更が可能なため、設定変更により事象を解消できる可能性があります。

ただ、 "デスクトップ ヒープの枯渇" という現象が具体的にどういうものなのか疑問に思われる方も多いのが実情です。
実際に、マイクロソフトにいただくお問い合わせの中でも、デスクトップ ヒープの枯渇とはいったい何なのか詳しく説明してほしいとのご意見をよく頂戴します。
そこで、今回は、デスクトップ ヒープが何なのかについてもご説明したうえで、デスクトップ ヒープ枯渇の回避方法についてご紹介します。

もくじ

  1. デスクトップ ヒープとは何か
  2. デスクトップ ヒープのサイズ上限とデスクトップ ヒープの枯渇
  3. デスクトップ ヒープ枯渇の回避 - デスクトップ ヒープのサイズ上限の拡張
  4. デスクトップ ヒープ枯渇の原因調査
  5. おわりに

デスクトップ ヒープとは何か

デスクトップ ヒープとは、 Windows 上で作成されるデスクトップに紐づけられる、ウィンドウやメニューなどの情報を格納する領域です。

デスクトップ ヒープの根底には、セッション、ウィンドウ ステーション、デスクトップの 3 つの概念があります。
あるユーザーがログオンすると、 Windows の内部ではユーザーのためにセッションが新たに作られます。
(例外として、サービスやタスクの起動のような非対話型の認証が生じた際には、新たなセッションは作られず、共用のセッション Session 0 が使用されます。)
セッションの内部にはウィンドウ ステーションが作成され、ウィンドウ ステーションのさらに内部にデスクトップが作成されます。
デスクトップ上には、実際にユーザーに見えるウィンドウやテキスト ボックスのようなオブジェクト (ユーザー オブジェクト) が作成されますが、このユーザー オブジェクトの情報を保持するのに使用されるのが、デスクトップ ヒープです。

+++ 参考 +++
セッション・ウィンドウ ステーション・デスクトップの概念については、下記ページでも詳細に触れられています。
"USER オブジェクトと GDI オブジェクト – 第 1 部"
https://technet.microsoft.com/ja-jp/windows/mark_16.aspx
++++++++++

デスクトップ ヒープの新規割り当てができなくなると、ウィンドウなどの GUI に必要なデータ構造を作成することができなくなり、アプリケーションの起動失敗などが発生します。

余談とはなりますが、上述のとおり Windows ではユーザーごとにセッションが作成され、セッション稼働中ウィンドウ ステーションは配下のデスクトップを切り替えながら画面に出力しています。
この仕組みには、次のようなメリットがあります。

  • 同一デスクトップ内の GUI の管理に際し、デスクトップ ヒープを介したデータやコードの共有が容易かつ安全にできる。
  • セッション・デスクトップごとのメモリの境界が明確であり、異なるセッション・デスクトップの影響を受けにくい。
    特に、ログオン画面や UAC のプロンプト画面は専用のデスクトップを使用しているので、通常のデスクトップの影響を受けにくく、セキュリティ上の脅威を緩和できる。

デスクトップ ヒープのサイズ上限とデスクトップ ヒープの枯渇

Windows Server 2008 以降 (Windows Server 2008 R2, Windows Server 2012R2 や Windows Server 2016) では、対話型・非対話型のデスクトップ ヒープのサイズ上限が、既定値が以下のように設定されています。

    対話型: 20480 KB
非対話型: 786 KB

なお、対話型デスクトップとは、通常一般ユーザーが使用するデスクトップで、物理的な画面やキーボードを通じてユーザーとのやり取りが可能なデスクトップです。
一方で、非対話型デスクトップは、サービスやログオン状態にかかわらず実行するように設定されているタスクなど、ヘッドレスの状態で動作するプロセスが使用するデスクトップとして用意されます。

ここで重要なことは、非対話型デスクトップのヒープ サイズ上限は、対話型よりも小さく設定されており、対話型のデスクトップ ヒープよりも枯渇しやすいということです。
本来非対話型のセッションでは GUI を必要としないため、非対話型デスクトップのサイズ上限を厳しくすることは合理的な設計と言えますが、
アプリケーションの挙動次第では、内部的に作成される GUI オブジェクトによりデスクトップ ヒープが消費されてしまうため、結果としてデスクトップ ヒープが枯渇しやすくなってしまうのです。
現に、マイクロソフトのサポートには年間数十件ほどのペースでデスクトップ ヒープの枯渇に関するお問い合わせを頂戴しますが、そのほとんどで非対話型デスクトップ ヒープの枯渇が問題となっています。

デスクトップ ヒープが枯渇すると、新たなユーザー オブジェクトを作成することができなくなるため、ウィンドウなどの GUI の維持に必要なデータが配置できず、結果としてアプリケーションの起動失敗や、サービスによりバックグラウンドで実行されるバッチ処理の実行失敗につながります。

殊によくあるのが、大量のバッチ処理をサービスとして並行実行することで、デスクトップ ヒープが枯渇し、バッチ処理の実行が途中で失敗してしまうというケースです。
cmd.exe と cmd.exe に付随して起動される conhost.exe は、非対話型デスクトップ上でもそれぞれウィンドウやメニュー バー、キャレットを持つため、デスクトップ ヒープを若干 (一般的には数 KB) 消費します。
そのため、非対話型のセッションで多数のバッチ処理を並行して実行すると、小さな消費の積み重ねでデスクトップ ヒープを消費しきってしまい、結果としてデスクトップ ヒープが枯渇した状態になります。

+++ 検証 +++

バッチ処理の並行実行による非対話型のデスクトップ ヒープの枯渇は、下記のように無限ループするバッチ ファイルを使用して簡単に再現することができます。

重要: 下記は事象の理解の補助のために紹介するものであり、一般ユーザーによる実施を意図したものではありません。
本手順を実際に実行したことによるシステム・データへの損害につきましては、責任を負いかねます。

  1. 下記一行が書かれたバッチ ファイル cmd-loop.bat をデスクトップ上に作成します。

    start cmd.exe /K %USERPROFILE%\Desktop\cmd-loop.bat

  2. タスク スケジューラーにて、 cmd.exe を引数 "/K %USERPROFILE%\Desktop\cmd-loop.bat" で実行するタスクを作成します。
    タスク作成の際には、 [全般] タブの [セキュリティ オプション] の項目で [ユーザーがログオンしているかどうかにかかわらず実行する] が選択されていることを確認します。

  3. 作成したタスクを手動で実行します。

手元の検証環境で実際に検証したところ、下記事象が確認できました。

  1. タスク マネージャー上で大量の conhost.exe がセッション ID 0 で稼働しているのが見える (実際には 111 個稼働している)。

  2. システムのイベント ログにイベント ID 243 が記録される。

  3. 事象発生時のダンプを解析すると、 Session 0 (非対話領域) のとあるデスクトップのヒープが枯渇状態となっている。

    **************** > !dskheap -s 0 Winstation\Desktop Heap Size(KB) Used Rate(%) ------------------------------------------------------------ WinSta0\Default 20480 0% // 各セッションにかならず作られる対話型デスクトップ。 Session 0 は非対話型ユーザー セッションなので、原則として使用されない。 WinSta0\Disconnect 96 4% WinSta0\Winlogon 192 2% // ログオン画面で使用するデスクトップ。 Service-0x0-3e7$\Default 768 2% // サービスとして利用されるデスクトップ。サービスの実行ユーザーごとにデスクトップが異なる。 Service-0x0-3e5$\Default 768 0% Service-0x0-3e4$\Default 768 0% Service-0x0-53f57$\Default 768 99% // タスクが実行されているデスクトップ。非対話型。ヒープの使用率が 99 % と枯渇状態。枯渇がどのウィンドウ ステーション・デスクトップで発生するかは、システムの稼働状況に依存。 ****************

デスクトップ ヒープ枯渇の回避 - デスクトップ ヒープのサイズ上限の拡張

デスクトップ ヒープ枯渇の回避方法としては、次の 2 通りが考えられます。

  1. デスクトップ ヒープの枯渇を引き起こしているアプリケーションの改修
  2. デスクトップ ヒープのサイズ上限の拡張

デスクトップ ヒープのサイズ上限を拡張する方が工数も圧倒的に少なく行えるため、お問い合わせいただいたケースのほとんどでは、サイズ上限の拡張により事象を回避しています。
中には、デスクトップ ヒープの枯渇が発生することを見越して、サーバー構築時の一手順としてデスクトップ ヒープのサイズ上限を拡張しておくお客様もいらっしゃいます。

デスクトップ ヒープのサイズ上限は、下記のレジストリ項目で変更することができます。

場所:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SubSystems
名前:Windows
種類:REG_EXPAND_SZ
データ: SharedSection=XXX,YYY,ZZZ の部分

SharedSection の 1 番目の値 (XXX): 全てのデスクトップに共有されている標準ヒープ
SharedSection の 2 番目の値 (YYY): インタラクティブ (対話型) デスクトップ ヒープの値
SharedSection の 3 番目の値 (ZZZ): ノン インタラクティブ (非対話型) デスクトップ ヒープの値

上記 SharedSection の 2 番目や 3 番目の値を大きくすることで、デスクトップ ヒープのサイズを大きくすることができます。

当該箇所は、長いレジストリ値の一部に含まれていますので、レジストリ エディターで確認する際には、手動でカーソルを動かして表示させる必要があります。
また、 SharedSection に誤った値 (たとえば数字以外の文字列) を指定すると、システムが正常に起動しなくなるので、注意してください。

デスクトップ ヒープ拡張の際には、一般的に、既定値の 2 倍から 3 倍を目安に、徐々に大きくすることをおすすめしています。
値を大きくすることですぐに何か問題が生じるようなことはありませんが、上述したように、上限が緩和され、デスクトップ ヒープが肥大化するようになると、かえってパフォーマンスの低下 (デスクトップ ヒープの使用による空きメモリの逼迫や並行するプロセスの増加による処理遅延) を引き起こす可能性があります。
そのため、事象の解消とパフォーマンスへの新たな影響を見ながら、段階的にデスクトップ ヒープのサイズを拡大するようお願いしています。

デスクトップ ヒープ枯渇の原因調査

デスクトップ ヒープの消費状況や枯渇の原因の調査の際には、まず完全メモリ ダンプの採取が可能であるかどうかをご確認いただければと思います。

Windows Server 2003 や Windows XP の時代には、 Desktop Heap Monitor と呼ばれるツールが一般公開されており、デスクトップ ヒープの状況を簡単に調査することが可能でした。
一方で、 Windows Server 2008 / Windows Vista 以降では、古いツールが使用できなくなっています。

Windows Server 2008 / Windows Server 2008 R2 の場合は、デバッガーや LiveKD を使用してお客様環境でも調査がある程度できましたが、
Windows Server 2012 以降の場合は、完全メモリ ダンプをご採取いただき、デスクトップ ヒープの観点でのダンプの解析をマイクロソフトのサポートにご依頼いただく必要があります。

調査を迅速に進めるためにも、デスクトップ ヒープ関連の問題を調査したい場合は、こちらの記事を参考に完全メモリ ダンプを採取し、マイクロソフトのサポートまで解析をご依頼ください。

おわりに

デスクトップ ヒープの枯渇は、特にバックグラウンドでのバッチ処理を行うようなサーバー環境で起きやすく、デスクトップ ヒープ枯渇に関する調査は多くお問い合わせを頂戴するトピックにもなっています。
他方、デスクトップ ヒープ枯渇の原因調査にはダンプの採取が必要となる場合が多く、原因調査のハードルは高めであるといえます。

デスクトップ ヒープの拡張は、すぐにシステムの稼働に影響を与えるような作業ではありません。
マイクロソフトが把握している事例においても、デスクトップ ヒープを 2 倍から 3 倍程度増やしたことで他の問題が発生したとの報告はない状況です。
そこで、

  • 他のアプリケーションは正常に動いているのに、アプリケーションの起動やバッチ処理に失敗する。
  • イベント ID 243 や 244 が記録される。
  • 例外コード 0xc0000142 でイベント ID 1000 が記録される。

このような事象が発生した際には、まずは上記でご紹介したレジストリ変更を実施し、事象が回避できるかどうかをお試しいただければと思います。
デスクトップ ヒープの拡張でも事象が解消しない場合には、お気軽にマイクロソフトのサポートにご相談いただければ、課題解決にむけ可能な限りご支援させていだきます。

アプリケーションの起動やバッチ処理に失敗する問題について、詳細な調査をご希望の場合は、まずは完全メモリ ダンプのような再起動を伴う情報採取が可能かどうかをご確認いただいたうえで、マイクロソフトのサポートにお問い合わせいただけますと幸いです。