簡単なmalloを実現します.

4265 ワード

原文:http://www.ibm.com/developerworks/cn/linux/l-memory/ 参考:http://www.geeksforgeeks.org/memory-layout-of-c-program/
Cプログラムメモリレイアウト
Cプログラムのメモリレイアウトは、下図のようになります.实现一个简单的malloc_第1张图片
heap
図中のheapはヒープスペースであり、その開始位置はbssセグメントの最後にあり、終了アドレスはsbrk(0)を呼び出して取得することができます.図のようにheapは高いアドレスに拡張されます.通常、ライブラリ関数malloc、freeを使用して、ユーザーのためにheap上にダイナミックメモリを割り当ててリリースします.malloc、freeは下の階でsbrakあるいはmmapを通じて実現しました.
sbrak&mmap
UNIXベースのシステムは、付加メモリにマッピングできる2つの基本システムの呼び出しがあります.システムの中断点を覚えていますか?この位置はプロセスマッピングのメモリ境界です.sbrk()はこの位置を前に進むか後ろに動かすだけで、プロセスにメモリを追加したり、プロセスからメモリを取り出すことができます.mmap:mmap()というか、「メモリイメージ」というか、brak()に似ていますが、より柔軟です.まず、プロセスに限らず、どの位置のメモリも写像できます.次に、仮想アドレスを物理のRAMまたはswapにマッピングするだけでなく、ファイルとファイルの位置にマッピングすることもでき、このようにして、読み書きメモリはファイル中のデータを読み書きします.しかし、ここでは、プロセスにマッピングされたメモリを追加する能力だけに関心があります.munmap()したことはmmap()とは反対です.あなたが見ているように、brak()やmmap()は私たちのプロセスに追加の仮想メモリを追加するために使用できます.私達の例ではbrak()を使用します.もっと簡単で、もっと通用します.
次に自分のハローcとfreeを実現してみましょう.
簡単なmalloを実現します.
まず、mallocとfreeのインターフェースを定義します.
void * hmalloc(size_t size);
void hfree(void *mem);
私たちはheapをメモリ区間と見なして、「heapp ustart,heapp uend」を使って、彼らはグローバル変数です.
void *heap_start = 0;
void *heap_end = 0;
初めてhmallocを使う時はこの区間を初期化しなければなりません.最初の空きスペースは空です.
void hmalloc_init()
{
    heap_start = heap_end = sbrk(0);
}
ブロックごとに割り当てられたメモリについては、占有やサイズなどの情報を記録する必要があります.したがって、ブロックごとのメモリを定義するmetadataは以下の通りです.
struct hmem_meta {
    uint8_t is_available; /*      */
    size_t size; /*       ,  metadata */
};
私達のhmallecはユーザーに戻ったのはmetadata後のメモリエリアで、ユーザーがhfreeを呼び出して釈放する時あるptrを使う時、ptrにmetadataの固定オフセットの大きさを差し引くだけでmetadataの住所が得られます.hfreeの実現も簡単です.
void hfree(void *mem)
{
    if(!mem) return;

    struct hmem_meta *hmm = mem - sizeof(struct hmem_meta);
    hmm->is_available = 1;
}
最後に、hmallocを実現しましょう.私たちの分配戦略は簡単です.heapの区間から順番に探します.適当なものが見つからなかったら、sbrkを使ってheapの空間を増やします.
void * hmalloc(size_t n)
{
    if(!heap_start) hmalloc_init();

    n += sizeof(struct hmem_meta);

    void *memory_location = NULL;
    void *current_mem = heap_start;
    while(current_mem != heap_end)
    {
        struct hmem_meta *hmm = current_mem;
        if(hmm->is_available && hmm->size >= n)
        {
            hmm->is_available = 0;
            memory_location = current_mem;
            break;
        }
        current_mem += hmm->size;
    }

    if(!memory_location)
    {
        sbrk(n);
        memory_location = heap_end;
        struct hmem_meta *hmm = memory_location;
        hmm->is_available = 0;
        hmm->size = n;
        heap_end += n;
    }

    return memory_location + sizeof(struct hmem_meta);
}