記憶體分配 1 空閒鍊錶

2021-05-24 01:43:01 字數 1576 閱讀 6970

posted on

六月 29, 2007

byarrowpig1979

記憶體分配是所有成功的庫都要費大量心力去做好的事情,除非是對performance很高的需求,至少我現在在工作中很少需要自己來寫記憶體分配策略。我始終覺得一些經典的庫,像stl,loki,boost是最好的教材。讀書也要講究方法,讀stl這樣的庫,我現在會逼著自己多問幾個為什麼,為什麼作者要這樣設計呢,如果換作我自己,我會怎樣設計呢,有什麼地方沒有考慮周全呢。今天我試圖來說說記憶體分配,希望大家多發表意見。交流才能進步嘛-:)

我們經常會寫

cmyobject* pobj = new cmyobject(…);  // 從堆上分配乙個物件

其實編譯器會產生下面的**:

cmyobject* pobj;

trycatch( std::bad_alloc)

可以把::operator new()看作是malloc,其實這最終會導致乙個系統呼叫,去向系統要資源。在檔案i/o一樣,要提高讀寫速度,關鍵是要減少物理檔案i/o的次數(磁碟尋道,從物理磁碟讀寫),典型的解決方案就是buffer,每次我都多要一點,下次要讀得東西如果在buffer裡面,就不需要從磁碟拿了,畢竟記憶體操作要比磁碟操作快太多太多了。那自然就想到了,在記憶體分配中也一樣啊,要減少客戶程式實際向系統要記憶體的次數,我每次要得時候多要一點不就可以了嗎。是的,那在c++裡面怎麼實現呢?

在實現的時候有一點要求,就是分配程式的改動,因該盡最大可能不影響客戶程式**,最好一點影響也沒有

我的想法是這樣的:

在第一次需要分配乙個cmyobject物件的時候,我就分配100個sizeof(cmyobject)大小的記憶體,以後第二次要分配乙個cmyobject物件的時候,我就從上次剩下的99個後備中間拿乙個出來。為了達到這樣的目標,我可以維護乙個單向鍊錶,一開始把這100個物件串起來(這需要定義乙個成員變數next),還需要乙個指標,指向下乙個可供使用的物件(freestore)。

class cmyobject;

cmyobject* cmyobject::freestore = null;

void* cmyobject::operator new(size_t size)

// 從庫存中拿出第乙個,給請求的人

p = freestore;

freestore = freestore->next; // 調整freestore到下乙個空閒物件

return p;     }

下面我們看看釋放:

void cmyobject::operator delete(void* p,size_t)

整個過程就是這樣的,其實可以看成乙個邏輯上的stack,先reserve一下stack的大小為100,new的時候pop乙個出來,delete的時候push回去。

有兩個地方要注意了:

1. 這是個欠債不還錢的主哦,問系統拿的東西,不還的。要到程式退出的時候,才由程序負責清理。

2. 每次向系統索要記憶體時,其實都會都要一點點用於記錄這塊記憶體的大小之類的,我猜至少是4個位元組,但是現在每個類都多了乙個額外的next指標的代價。似乎除了分配速度提高以外,在大小上沒有優勢。我們馬上會談到如何使用embedded pointer解決這個問題。

模擬記憶體分配 鍊錶實現

我們擁有長度為m位元組的記憶體,輸入的第一行是兩個整數,分別代表對記憶體的操作次數以及m的大小,輸入的第二行是乙個字串,也就程式中 所支援的三種操作 1.alloc n 分配n位元組的連續記憶體,並輸出被分配的記憶體塊的id 2.erase x 釋放id為x的記憶體塊 3.defragment 對記...

記憶體分配 1

記憶體分配方式有三種 1 從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的整個執行期間都存在。例如全域性變數,static 變數。2 在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集...

C語言記憶體的動態儲存管理2 空閒鍊錶

空閒鍊錶三種結構形式 1 所有請求的記憶體大小相同。這是一種最簡單的動態儲存管理方式。對此,系統通常的做法是 a 系統啟動時,將記憶體按大小均分成若干個塊,並形成乙個鍊錶。b 分配時,只需將鍊錶中第乙個節點分配給使用者即可,無需掃瞄整個鍊錶。c 時,將空閒塊插入到煉表頭即可。2 所有請求的記憶體大小...