我們知道,
c++中當我們用
new在堆中建立乙個物件時,會發生兩件事情。首先呼叫
operator new
分配一定大小的記憶體空間,然後在此空間上呼叫建構函式以形成物件。而
operatornew
涉及到尋找合適記憶體的演算法,往往,這個演算法是比較費時間的,所以,如果我們的程式中需要不斷的產生和釋放某型別的物件,那麼
operatornew
所累計起來的時間可能就會成為阻礙程式效能提高的乙個重要因素了。看來我們確實有必要為這種情況提供一種恰當的方案以實現快速記憶體分配。
先看看我們所處的環境。我們有乙個自定義的型別(即乙個
class
),而我們的程式需要不斷的產生和釋放此型別的物件,而產生此物件時需要的
operator new
是比較費時間的。我們將在如何縮小
operatornew
操作的時間這個問題上努力?再深入一步想,我們用
new分配記憶體生成物件,然後釋放該記憶體,接著又重複同樣的故事。呵,你可能有方案了,是嗎?
是的,我們可以在釋放記憶體的時候,並不是真的釋放記憶體,而是將指向該記憶體的指標維護起來,等到需要分配記憶體,就不用再呼叫記憶體分配演算法了,直接將維護的指標返回就行了。我們可以將這中策略封裝在乙個基類
memorymanage
中,如果你的自定義模擬如
derived
類需要採用這種記憶體分配方案,那麼讓
derived
公共繼承
memorymanage
就行了。
我們可以用乙個記憶體塊鍊錶來維護被釋放的記憶體塊。根據「
is_a
」關係,即乙個
derived
物件就是乙個
memorymanage
物件,所以我們可以在
memorymanage
類中新增乙個(
memorymanage*
)型的指標,讓其指向下一塊需要維護的記憶體。另外我們需要乙個
memorymanage
物件來維護這個記憶體塊鍊錶的
head
,這可以使其成為
memorymanage
類的乙個靜態成員。
記憶體塊鍊錶的布局大致如下圖。
接下來,我們要重寫
operator new
和operator delete
,以覆蓋掉預設的記憶體分配方式。
memorymanage
類的主要**如下。
class memorymanage
//設定
next
指標初值
void* operator new(size_t size)//
重定義operator new
else}
void operator delete(void* pp)//
重定義operator delete
};memorymanage* memorymanage::listhead = null ; //
初始化靜態成員
如果我們想當鍊表中維護的記憶體個數超過一定數量
n(比如
50)時,如果還有物件要釋放,我們就不將其記憶體新增到鍊錶中了,而是直接釋放掉。這可以在
memorymanage
類中增加乙個靜態成員
count
來實現。
首先,在
memorymanage
類中宣告這個成員,然後初始化為0。
static int memorymanage ::count = 0 ;
然後改寫
operator new
和operator delete
。void* operator new(size_t size)//
重定義operator new
else
}void operator delete(void* pp)//
重定義operator delete
else
}
我們似乎應該提供乙個函式,讓使用者在適當的時候,可以釋放掉記憶體塊鍊錶中維護的所有記憶體。於是在
memorymanage
類中增加乙個靜態的
freeallspace
函式。如下
static void freeallspace(void)}
似乎一切都很好的解決了,是嗎?好,來看看下面的例子。
class student:public memorymanage
void display()};
class teacher:public memorymanage
void display()};
void main(void)
執行一下,得到了什麼結果?輸出好像是沒有什麼問題,而實際上記憶體管理已變得相當混亂。注意到
sizeof
(teacher
)比sizeof
(student
)大,而在程式執行的過程中,我們將只有
sizeof
(student
)大小的空間分配給了乙個大小為
sizeof
(teacher
)的teacher
物件,這肯定會覆蓋掉原空間相鄰記憶體中的其它資料,如果被覆蓋掉的正好是重要的資訊,那麼程式的執行結果是可想而知的。
難道沒有辦法了嗎?如果我們
student
物件由乙個鍊錶來管理,而
teacher
物件由另乙個鍊錶來管理,而且所有一切需要按此策略分配的型別的物件都由它自己的特定鍊錶來管理,那就可以了啊。怎麼做了?其實我們只要將
memorymanage
類宣告為模板就可以了,像這樣:
template
class memorymanage //
其它一切保持不變!
另外靜態成員的初始化要修改一下:
template
memorymanage* memorymanage::listhead = null ;
template
static int memorymanage ::count = 0 ;
然後定義
student
類和teacher
類時,讓它們以自己型別名作為模板引數從
memorymanage
繼承就可以了,像這樣:
class student:public memorymanage //
其它一切不變!
class teacher:public memorymanage< teacher > //
其它一切不變!
再執行一下上面的
main
函式,你會發現已經可以完全正確執行了。因為現在每乙個類(如
student
或teacher
)都有它自己的記憶體管理鍊錶,這個鍊錶中所有的指標型別是完全一樣的,當然,它們所指向的記憶體塊的大小也是一樣的。如此以來,前面出現記憶體管理混亂的問題就解決了。上面的解決方案很簡單,僅僅是將
memorymanage
只 要我們在進行程式設計,特別是在進行系統級的程式設計時,記憶體管理是需要我們給予足夠關注的乙個方面,其中乙個基本的原則就是「時空互換」原則,也就是我 們在設計時應權衡是用空間換取時間(即為了提高執行的速度,而對記憶體的需求加大),還是反過來,用時間換取空間。本文所介紹的這種記憶體管理方法就是典型的 用空間換時間的處理方法。靈活地使用「時空互換」原則,我們可以自己設計出多種記憶體管理方案和其對應的演算法
C 快速記憶體分配
c 快速記憶體分配 zhuweisky 2003.12.10 我們知道,c 中當我們用 new在堆中建立乙個物件時,會發生兩件事情。首先呼叫 operator new 分配一定大小的記憶體空間,然後在此空間上呼叫建構函式以形成物件。而 operatornew 涉及到尋找合適記憶體的演算法,往往,這個...
C 快速記憶體分配
c 快速記憶體分配 zhuweisky 2003.12.10 我們知道,c 中當我們用 new在堆中建立乙個物件時,會發生兩件事情。首先呼叫 operator new 分配一定大小的記憶體空間,然後在此空間上呼叫建構函式以形成物件。而 operatornew 涉及到尋找合適記憶體的演算法,往往,這個...
C 記憶體分配
總結 1 從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的整個執行期間都存在。例如全域性變數,static變數。2 在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是...