システム領域メモリの割り当て

重要

このトピックで説明する ExAllocatePool DDI は、Windows 10 バージョン 2004 で非推奨となり、ExAllocatePool2ExAllocatePool3 に置き換えられました。 詳細については、「非推奨の ExAllocatePool 呼び出しを ExAllocatePool2 および ExAllocatePool3 にアップグレードする」を参照してください。

ドライバーは、デバイス固有の情報のグローバル記憶域として、 デバイス拡張機能 内のシステム割り当て領域を使用できます。 ドライバーはカーネル スタックのみを使用して、少量のデータを内部ルーチンに渡すことができます。 通常は I/O バッファー用ですが、一部のドライバーでは追加の大量のシステム領域メモリを割り当てる必要があります。

I/O バッファー領域を割り当てるために使用する最適なメモリ割り当てルーチンは、MmAllocateNonCachedMemoryMmAllocateContiguousMemorySpecifyCacheAllocateCommonBuffer (ドライバーのデバイスがバス マスター DMA またはシステム DMA コントローラーの自動初期化モードを使用している場合)、または ExAllocatePoolWithTag です。

非ページ プールは通常、システムの実行時に断片化されるため、ドライバーの DriverEntry ルーチンは、これらのルーチンを呼び出して、ドライバーが必要とする長期的な I/O バッファーを設定する必要があります。 ExAllocatePoolWithTag を除くこれらの各ルーチンは、(プロセッサのデータ キャッシュ ライン サイズによって決定される) プロセッサ固有の境界にアラインされたメモリを割り当てて、最適なパフォーマンスを提供します。

非ページ プール メモリは限られたシステム リソースであるため、ドライバーはできるだけ経済的に I/O バッファーを割り当てる必要があります。 通常、ドライバーは、これらのサポート ルーチンを繰り返し呼び出して、PAGE_SIZE未満の割り当てを要求しないようにする必要があります。これは、PAGE_SIZE未満の各割り当てには、内部的に割り当てを管理するために使用されるプール ヘッダーも付属しているためです。

ドライババッファー領域を経済的に割り当てるヒント

I/O バッファー メモリを経済的に割り当てるには、次の点に注意してください。

  • MmAllocateNonCachedMemory または MmAllocateContiguousMemorySpecifyCache を呼び出すたびに、要求された割り当てのサイズに関係なく、常にシステムのページ サイズ (非ページ システム領域メモリ) の倍数が返されます。 したがって、ページ未満の要求は完全なページに切り上げられ、ページ上の残りのバイトは無駄になります。関数を呼び出したドライバーはアクセスできず、他のカーネル モード コードでは使用できません。

  • AllocateCommonBuffer の各呼び出しでは、少なくとも 1 つのアダプター オブジェクト マップ レジスタが使用され、少なくとも 1 バイトと最大 1 ページがマップされます。 マップ レジスタと共通バッファーの使用の詳細については、 アダプター オブジェクトと DMAを参照してください。

ExAllocatePoolWithTag を使用したメモリの割り当て

ドライバーは、次のシステム定義の PoolType パラメーターの POOL_TYPE 値のいずれかを指定して ExAllocatePoolWithTag を呼び出すこともできます。

  • ドライバーが IRQL > APC_LEVELで実行中にアクセスする可能性がある、デバイス拡張機能またはコントローラー拡張機能に格納されていないオブジェクトまたはリソースの PoolType = NonPagedPool

    この PoolType 値の場合、 ExAllocatePoolWithTag は、指定された NumberOfBytes がPAGE_SIZE以下の場合に要求されるメモリの量を割り当てます。 それ以外の場合、最後に割り当てられたページの残りのバイトは無駄になります。呼び出し元にはアクセスできず、他のカーネル モード コードでは使用できません。

    たとえば、x86 では、5 キロバイト (KB) の割り当て要求では、2 つの 4-KB ページが返されます。 2枚目のページの最後の 3 KB は、呼び出し元または別の呼び出し元では使用できません。 非ページ プールの無駄を回避するために、ドライバーは複数のページを効率的に割り当てる必要があります。 例えばこの場合ドライバーは、PAGE_SIZE 用と1 KB用の 2 つの割り当てを行うことができ、合計で 5 KBを割り当てます。

    Windows Vista 以降では、システムによってメモリが自動的に追加されるため、2 つの割り当てが不要になります。

  • IRQL <= APC_LEVELで常にアクセスされ、ファイル システムの書き込みパスにないメモリのPoolType = PagedPool

要求されたバイト数を割り当てることができない場合、ExAllocatePoolWithTagNULL ポインターを返します。 ドライバーは返されるポインターを常に確認する必要があります。 値が NULL の場合、 DriverEntry ルーチン (または NTSTATUS 値を返すその他のドライバー ルーチン) は、STATUS_INSUFFICIENT_RESOURCESを返すか、可能であればエラー状態を処理する必要があります。