メモリ割り当てに関するすべての記事は、メモリ割り当て方法を説明したり、ヒープとの関係を考慮せずに使用するmmap
方法を説明しているようです。sbrk
私はヒープがメモリ割り当てでほとんど重要ではない役割を果たしていることがわかりました。実際、それが何をしているのかはよくわかりません:D、誰かが私を混同しないように頼みます。
これが私が理解する方法です。
1)メモリが割り当てられると、初期化されていないデータセグメントの終わりであるBSSが拡張される。これらの拡張(x
たとえば、アドレスの移動x-n
)は呼び出しの結果として発生しますsbrk
。このモデルでは、n
BSSセグメントの先頭のバイト数を減らすためにメモリが割り当てられます(各アドレスに対して1バイトの仮定)。sbrk
このモデルは現在廃止されました。一部の人々はヒープをそのようなすべての拡張の集合空間として定義します。他の人はそうではありません。後者の場合、ヒープは何をしますか?
2) 最新のメモリ割り当て方式ではヒープが存在します(何の理由なのかわかりません)。メモリを割り当てるために、データはページコレクションとしてメモリ領域にmalloc
内部的に格納されます。mmap
これらのメモリ領域はヒープとは無関係です。
要約:
以前のシステムの場合:エンドBSSでオフセットを増やした後に得られたアドレス空間にメモリ割り当てが保存されると、ヒープは使用されますか?
最新のシステムの場合:mmapが主にメモリ割り当てに使用されると仮定すると、ヒープの目的は何ですか?
どちらの場合も、ヒープは実際にどのように使用されますか?
答え1
mmap
sbrk
プロセスにアドレス空間を割り当てるためにカーネルが提供するシステムコール。これらの呼び出しは、仮想アドレスのマッピングを物理ページフレームに変更します。これらのマップのアドレス制限を超えたメモリアドレッシングは厳密に禁止され、分割エラーが発生します。これはカーネルがプロセスに提供する低レベルのインタフェースです。brk
アドレスで終わるメモリ領域を通常ヒープと呼びます。
malloc
カーネルはまたはについて何も知りませんfree
。これはlibcのライブラリ関数です。 Libcはデータ構造を保持し、メモリ割り当ての観点からどのメモリ領域が空であるかを記録します。たとえば、Libcが動的メモリ割り当てを実装する方法にmalloc
応じてマッピングを拡張します。sbrk
mmap
malloc
答え2
「ヒープ」は、低レベルの実装ではなく、高レベルのアイデアです。 C言語では、ヒープは割り当てをmalloc()
提供するために使用されるメモリプールです。
以下は、楽しくシンプルなメモリアロケータの実装です。
static char *heap[1000000];
int top = 0;
void *malloc(int size) {
void *ret = &heap[top];
top += size;
return ret;
}
void free(void *ptr) {
/* Eh; freeing is too hard */
return;
}
これは悪いアロケータですが、正しい種類のプログラムの場合は、システムとコンパイラがメモリの並べ替えなどを受け入れると機能します。ヒープは配列であり、配列をheap[]
使用またはアセンブルするのではなく、配列宣言を使用してコンパイル時にビルドします。sbrk()
mmap()
「実際の」アロケータは同じように動作します。呼び出されると、malloc()
メモリプール(ヒープ)の小さな部分を占有し、その割り当てのために予約されます。 2つの重要な違いがあります。
- 実際のアロケータは、
free()
後で再利用できるように割り当てる方法を知っています。 - 既存のブロックがすべていっぱいになると、物理アロケータはオペレーティング
sbrk()
システムにより多くのメモリを要求して(または使用)ヒープサイズを増やすことができます。mmap()