Subscribed unsubscribe Subscribe Subscribe

ERROR_OUTOFMEMORY と ERROR_NOT_ENOUGH_MEMORY の違いを探る

Win32 error

Win32 API (システムコールというと語弊があるので) 共通エラーコードの中には、なぜかほとんど同じ意味のものが 2 つあります。一つは ERROR_NOT_ENOUGH_MEMORY で、もう一つは ERROR_OUTOFMEMORY です。UNIX でいうところの ENOMEM ですね。

以下、ヘッダファイルの定義から引用します。

  • ERROR_NOT_ENOUGH_MEMORY
//
// MessageId: ERROR_NOT_ENOUGH_MEMORY
//
// MessageText:
//
//  Not enough storage is available to process this command.
//
#define ERROR_NOT_ENOUGH_MEMORY          8L    // dderror
  • ERROR_OUTOFMEMORY
//
// MessageId: ERROR_OUTOFMEMORY
//
// MessageText:
//
//  Not enough storage is available to complete this operation.
//
#define ERROR_OUTOFMEMORY                14L

はてさて、まったく違いが分からない…。ぐぐっても、どこにも違いについて述べているような文章を見つけることができなかったので、自分で調べることに。

まずは、ERROR_NOT_ENOUGH_MEMORY と ERROR_OUTOFMEMORY の両方を返す API 関数があるかを探ってみます。どうやらいくつかあるようですが、TraceEvent() が見つかりました。

以下エラーコードの説明を抜粋。

ERROR_NOT_ENOUGH_MEMORY
The session ran out of free buffers to write to. This can occur during high event rates because the disk subsystem is overloaded or the number of buffers is too small. Rather than blocking until more buffers become available, TraceEvent discards the event. Windows 2000 and Windows XP: Not supported.
ERROR_OUTOFMEMORY
The event is discarded because, although the buffer pool has not reached its maximum size, there is insufficient available memory to allocate an additional buffer and there is no buffer available to receive the event.

どうやら2つのメモリ欠乏状態を区別しているようですが、これを見てもまだよくわかりません…。この関数は NT 系でしかサポートされていないようなので、NT エラーコードと WIN32 エラーコードのマッピングから探ってみることにしました。

INFO: Mapping NT Status Error Codes to Win32 Error Codesという資料がありましたので、ここから関連するエントリだけ抜き出してみました。

STATUS_SECTION_NOT_EXTENDED ERROR_OUTOFMEMORY
STATUS_SECTION_TOO_BIG ERROR_NOT_ENOUGH_MEMORY
STATUS_NO_MEMORY ERROR_NOT_ENOUGH_MEMORY
STATUS_TOO_MANY_PAGING_FILES ERROR_NOT_ENOUGH_MEMORY

NT のエラーコードの名称から察するに

  • 一般的なメモリ不足の状況は ERROR_NOT_ENOUGH_MEMORY となる。
  • メモリをまだ使い果たしてはいないが、操作を完了するに十分なメモリがない場合は STATUS_SECTION_NOT_EXTENDED がエラーとして返され、最終的に ERROR_OUTOFMEMORY に翻訳される。

なのではないかと思われましたが、でも、これらのエラーコードは SetLastError() を通じてユーザランドでも使われていることから、結局のところセマンティクスの違いというのはサブシステムに依っていて、一義的な解釈はない、という結論に達しました。