it-swarm-ja.com

Windowsは使用中のメモリ位置をどのように追跡しますか?

メモリリークの(基本的な)定義についての私の理解は、予約されたメモリ内の場所ですが、メモリを予約したアプリケーション内のそのメモリへのポインタが削除/失われました。

私の質問はこれです:Windows(または実際に任意のオペレーティングシステム)がメモリがまだ予約されていることを認識するためにに使用されたポインタの破壊後アプリケーション内でそのメモリを管理するには、使用中のメモリを個別に追跡する必要があります。 これはどこでどのように行われますか?

1
Ieuan Stanley

正解です。すべてのオペレーティングシステムは、メモリの使用と割り当てを個別に追跡します。これはその重要な機能の1つです。多くの理由で、メモリの完全な制御をユーザーランドプロセスに渡すことは単に意味がありません-セキュリティは一例として指摘できます:プロセスは機密情報をメモリに保存できるため、オペレーティングシステムはどのプロセスが許可されるかを管理する必要がありますアクセスします。

通常、すべてのオペレーティングシステムには、仮想メモリを追跡するMemory Management(またはWindowsのMemory Manager)という名前のサブシステムがあります。次に、OSの別の部分であるハードウェア抽象化により、この仮想メモリが物理デバイスにマップされます。もちろん、これにより、ユーザープロセスと物理メモリ間の直接的なやり取りが禁止されます。

オペレーティングシステムのこの部分と直接対話することは、パブリックAPIを介して部分的に利用できます-Windowsの場合は メモリ管理関数 を参照してください。 Linuxでは、メモリにアクセスする方法がいくつかあります。 このページ それを始めるのに最適な方法です。

2
Marek Rost

ええ、そうです、それはメモリマネージャと呼ばれるOSの一部の機能ですが、実際にはそれは問題を少し先に進めます。 OPは「どこで」だけでなく「どのように」と尋ねました....だから、ここに方法があります。

Windowsメモリマネージャー(略称Mm)は、仮想アドレス記述子と呼ばれるデータ構造のセットを介して仮想アドレスの使用中のスパンを追跡します。ユーザーモードのアドレス空間の場合、これはプロセスごとに行われます。プロセスが最初に作成されたとき、VADはありません。仮想アドレス空間のチャンクが空きから非空きに変わると(非空きは予約、コミット、マッピング、または1つまたは2つのあまり一般的でないオプション)、VADが作成されます。 VADには、領域の開始アドレス(常にページ整列)とサイズ(常にページ整列)、割り当てタイプ(予約済み、コミット済みなど)、およびその他のいくつかのものが含まれています。

VADによって記述された領域は、再定義および/または細分化することができます。たとえば、予約範囲が広い場合、それ自体の一部が「コミット済み」に変更されることは非常に一般的です。これにより、予約領域の新しい長さを反映するように元のVADが変更され、コミットされた領域を記述するために新しいVADが作成されます。コミットされた領域が元のVADで定義された範囲の「中央」から外れる場合は、2つの新しいVADを作成する必要があります。

各プロセスのVADは、平衡二分木、より具体的にはスプレーツリーと呼ばれるタイプのツリー構造に編成され、それぞれの開始仮想アドレスの順に並べられます。領域。特定のアドレスが使用されているかどうか、使用されている場合はどのように使用されているかを判断しようとすると、メモリマネージャはツリーを「ウォーク」して、アドレスを含むVADを見つけます(存在しない場合)。

このタイプのツリーの性質上、この操作は、既存のVADの検索と、VADの追加および削除の両方で非常に効率的です。既存のVADを見つけるには、単純な順序付きリストで「バイナリ検索」が効率的であるのと同じように効率的です。たとえば、ツリーに31から64のVADがある場合、任意のアドレスを検索するには、最大6つのVADを調べる必要があります。 65〜128のVADの場合、検索には7つの手順などが必要です。ただし、単純な順序付きリストとは異なり、エントリを追加または削除するために、既存のすべてのエントリを再シャッフルする必要はありません。

新しい領域を割り当てる必要がある場合、十分なサイズの空き領域を見つけるためにツリーを「ウォーク」する必要があります。これは適度にコストのかかる操作ですが、それほど頻繁には発生しないため、問題ありません。

「ポインタの破壊」に関して-ポインタはメモリ内の単なる場所です。仮想メモリを割り当てると(Windows APIでは、これに対する低レベルの呼び出しはVirtualAllocです)、割り当てられた領域へのポインターを取得します。ポインタをゼロで上書きしたり、ポインタが格納されている仮想メモリの割り当てを解除したりしても、OSにリージョンの処理が完了したことは通知されません。結局のところ、私はそのポインタ値を別の場所にコピーした可能性があります。 OSに「私はその地域で終わりました」と言うのは、VirtualFreeの呼び出しです。これにより、その領域を説明していたVADが削除されます。もちろん、プロセスごとのすべての仮想アドレス空間はプロセスの属性であり、プロセスが削除されると、まだ割り当てられているものはすべて消えます(すべてのVADもなくなるため)。

仮想ページ番号と物理ページ番号の関連付けは、ページテーブルと呼ばれる構造で維持されます。これらは、仮想アドレス空間の管理にも役立ちます。 512 ページテーブルエントリで構成され、仮想アドレス空間の2MBごとに1ページを占めるページテーブルがあります。各PTEは1ページを記述します。 PTは、32ビットx86では3レベル、x64では4レベルの単純な階層構造に編成されています。 v.a.sの2MBスパンに対応するページテーブルすべて無料(つまり、2 MBの内容を表すVADがない)は実際には存在しません。したがって、上位レベルのPTの対応するエントリはゼロです。ページテーブルも、OSのメモリマネージャーによって維持および更新されます(別の回答で主張されている「ハードウェア抽象化レイヤー」ではありません)。

(前の段落では、x86でPAEを想定しています。PAEがない場合、PTあたり1024 PTEであり、ツリーには2レベルのPTしかありません。)

さらに別のデータセットである「PFN配列」は、すべての物理ページの状態を追跡します。これは、物理ページ番号(「ページフレーム番号」)でインデックス付けされた構造の単純な配列です。配列の各要素には、対応する物理ページの状態に関する情報が含まれています。システム全体のページのどれがオンになっているのか(空き、スタンバイ、ゼロ化、変更済み)、または1つ以上のプロセスワーキングセットにある場合は、プロセスの数です。でなど。

1
Jamie Hanrahan