一:基本知識 在C++中,內(nèi)存分成5個區(qū),他們分別是堆、棧、自由存儲區(qū)、全局/靜態(tài)存儲區(qū)和常量存儲區(qū)。 1.堆區(qū)(heap)—就是那些由malloc 或 new 分配的內(nèi)存塊,他們的釋放編譯器不去管,由我們的應(yīng)用程序去控制,一般一個new就要對應(yīng)一個delete,malloc對應(yīng)free。如果程序員沒有釋放掉,那么在程序結(jié)束后,操作系統(tǒng)會自動回收。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表 2.棧區(qū)(stack)—就是那些由編譯器在需要的時候分配,在不需要的時候自動清除的變量的存儲區(qū)。由編譯器自動分配釋放,存放函數(shù)的參數(shù)值,局部變量的值,還保存了調(diào)用函數(shù)的返回地址等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。 4.常量存儲區(qū):存儲常量,如char *s="abcde"; 或者 const int i =10.程序結(jié)束釋放 5.程序代碼區(qū)存放函數(shù)體(類成員函數(shù)和全局函數(shù))的二進(jìn)制代碼。 【自由存儲區(qū),這應(yīng)該是一個運行時存在的堆。就是那些由malloc等分配的內(nèi)存塊,它和堆是十分相似的,不過它是用free來結(jié)束自己的生命的。 在函數(shù)體中定義的變量通常是在棧上,用malloc, calloc, realloc等分配內(nèi)存的函數(shù)分配得到的就是在堆上。在所有函數(shù)體外定義的是全局量,加了static修飾符后不管在哪里都存放在全局區(qū)(靜態(tài)區(qū)),在所有函數(shù)體外定義的static變量表示在該文件中有效,不能extern到別的文件用,在函數(shù)體內(nèi)定義的static表示只在該函數(shù)體內(nèi)有效。另外,函數(shù)中的"adgfdf"這樣的字符串存放在常量區(qū)。 二:堆和棧的理論知識 2.1申請方式
2.3申請大小的限制
2.5堆和棧中的存儲內(nèi)容 2.6存取效率的比較 char s1[] = \"a\"; char *s2 = \"b\"; a 是在運行時刻賦值的;而 b 是在編譯時就確定的;但是,在以后的存取中,在棧上的數(shù)組比指針?biāo)赶虻淖址?( 例如堆 ) 快。比如:
堆和棧的主要區(qū)別由以下幾點: 1 、管理方式不同; 2 、空間大小不同; 3 、能否產(chǎn)生碎片不同; 4 、生長方向不同; 5 、分配方式不同; 6 、分配效率不同; 管理方式:對于棧來講,是由編譯器自動管理,無需我們手工控制;對于堆來說,釋放工作由程序員控制,容易產(chǎn)生 memory leak 。 空間大?。阂话銇碇v在 32 位系統(tǒng)下,堆內(nèi)存可以達(dá)到 4G 的空間,從這個角度來看堆內(nèi)存幾乎是沒有什么限制的。但是對于棧來講,一般都是有一定的空間大小的,例如,在 VC6 下面,默認(rèn)的??臻g大小是 1M 。當(dāng)然,這個值可以修改。 碎片問題:對于堆來講,頻繁的 new/delete 勢必會造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個問題,因為棧是先進(jìn)后出的隊列,他們是如此的一一對應(yīng),以至于永遠(yuǎn)都不可能有一個內(nèi)存塊從棧中間彈出,在他彈出之前,在他上面的后進(jìn)的棧內(nèi)容已經(jīng)被彈出,詳細(xì)的可以參考數(shù)據(jù)結(jié)構(gòu)。 生長方向:對于堆來講,生長方向是向上的,也就是向著內(nèi)存地址增加的方向;對于棧來講,它的生長方向是向下的,是向著內(nèi)存地址減小的方向增長。 分配方式:堆都是動態(tài)分配的 ,沒有靜態(tài)分配的堆。棧有 2 種分配方式:靜態(tài)分配和動態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動態(tài)分配由 malloca 函數(shù)進(jìn)行分配,但是棧的動態(tài)分配和堆是不同的,他的動態(tài)分配是由編譯器進(jìn)行釋放,無需我們手工實現(xiàn) 。 分配效率:棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計算機(jī)會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。堆則是 C/C++ 函數(shù)庫提供的,它的機(jī)制是很復(fù)雜的,例如為了分配一塊內(nèi)存,庫函數(shù)會按照一定的算法(具體的算法可以參考數(shù)據(jù)結(jié)構(gòu) / 操作系統(tǒng))在堆內(nèi)存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由于內(nèi)存碎片太多),就有可能調(diào)用系統(tǒng)功能去增加程序數(shù)據(jù)段的內(nèi)存空間,這樣就有機(jī)會分到足夠大小的內(nèi)存,然后進(jìn)行返回。顯然,堆的效率比棧要低得多。 從這里我們可以看到,堆和棧相比,由于大量 new/delete 的使用,容易造成大量的內(nèi)存碎片;由于沒有專門的系統(tǒng)支持,效率很低;由于可能引發(fā)用戶態(tài)和核心態(tài)的切換,內(nèi)存的申請,代價變得更加昂貴。所以棧在程序中是應(yīng)用最廣泛的,就算是函數(shù)的調(diào)用也利用棧去完成,函數(shù)調(diào)用過程中的參數(shù),返回地址, EBP 和局部變量都采用棧的方式存放。所以,我們推薦大家盡量用棧,而不是用堆。 雖然棧有如此眾多的好處,但是由于和堆相比不是那么靈活,有時候分配大量的內(nèi)存空間,還是用堆好一些。 無論是堆還是棧,都要防止越界現(xiàn)象的發(fā)生(除非你是故意使其越界),因為越界的結(jié)果要么是程序崩潰,要么是摧毀程序的堆、棧結(jié)構(gòu),產(chǎn)生以想不到的結(jié)果。 三.new/delete 與 malloc/free 比較 從 C++ 角度上說,使用 new 分配堆空間可以調(diào)用類的構(gòu)造函數(shù),而 malloc() 函數(shù)僅僅是一個函數(shù)調(diào)用,它不會調(diào)用構(gòu)造函數(shù),它所接受的參數(shù)是一個 unsigned long 類型。同樣, delete 在釋放堆空間之前會調(diào)用析構(gòu)函數(shù),而 free 函數(shù)則不會。 class Time{ public: private: }; Time::Time(int h,int m,int s,string n){ hour=h; min=m; sec=s; name=n; cout<<"constructor of: "<<name<<endl; } int main(){ Time *t1; t1=(Time*)malloc(sizeof(Time)); free(t1); Time *t2; t2=new Time(0,0,0,\"t2\"); delete t2; system(\"PAUSE\"); return EXIT_SUCCESS; } 結(jié)果: constructor of: t2 destructor of: t2 從結(jié)果可以看出,使用 new/delete 可以調(diào)用對象的構(gòu)造函數(shù)與析構(gòu)函數(shù),并且示例中調(diào)用的是一個非默認(rèn)構(gòu)造函數(shù)。但在堆上分配對象數(shù)組時,只能調(diào)用默認(rèn)構(gòu)造函數(shù),不能調(diào)用其他任何構(gòu)造函數(shù) |
|