鏈表并不能解決堆中所有問題,還需要內(nèi)存池

堆和棧與靜態(tài)內(nèi)存分配不一樣,雖然都在進(jìn)程地址空間內(nèi),但是它們并沒有提前就分配好空間,而是在程序運(yùn)行的時(shí)候進(jìn)行分配,不過棧是操作系統(tǒng)自動分配和釋放,而堆是由開發(fā)人員根據(jù)具體需求進(jìn)行分配,釋放,這就是我們今天的主題,內(nèi)存的動態(tài)分配。

相信學(xué)過C語言直系親屬的C++、objective-C等語言的朋友們知道,在早期的時(shí)候,它們都需要手動的通過malloc函數(shù)進(jìn)行分配,然后又需要手動的進(jìn)行釋放(oc中是alloc和dealloc),不過這樣開發(fā)效率很低,往往會因?yàn)橐煤蛢?nèi)存忘記釋放出現(xiàn)各種奇葩問題。我記得當(dāng)時(shí)有人說過,用手動操作內(nèi)存,其編碼過程中消耗的時(shí)間要比使用ARC機(jī)制的編程語言多一倍左右。后來,隨著各種新的編程語言的出現(xiàn),其中又增加各種新的思維方式,有了ARC等垃圾自動回收機(jī)制后,在編碼過程中,編程人員不用再為內(nèi)存的釋放而操心,大大加快了編程速度,降低了編程的門檻。不過有一點(diǎn)要注意,C++和C至今還是沒有官方的ARC機(jī)制,不排除有大佬自己實(shí)現(xiàn)。

不過就我從以前學(xué)習(xí)objective-C時(shí)學(xué)習(xí)的MRC和后來使用的ARC來說,編碼速度確實(shí)使用ARC來的快,但是編譯和軟件的使用效率上看,ARC更容易出現(xiàn)卡頓等現(xiàn)象,說簡單點(diǎn),就是沒有以前那么順暢。如果多翻一翻GitHub上的一些大佬寫的項(xiàng)目,就會發(fā)現(xiàn)這些項(xiàng)目中,在比較關(guān)鍵的地方仍然使用MRC機(jī)制,手動的管理內(nèi)存的引用和釋放(Java很早就出現(xiàn)垃圾自動回收機(jī)制了)。我個(gè)人覺得培訓(xùn)班之所以能夠批量生產(chǎn)編碼員,就是因?yàn)楝F(xiàn)在語言不再讓程序員需要去考慮內(nèi)存管理等問題,全部交給計(jì)算機(jī)去處理了。

我們上面說了很多MRC和ARC等機(jī)制,實(shí)際上萬變不離其宗,終究是對內(nèi)存進(jìn)行動態(tài)的分配和釋放,所以我們先來說內(nèi)存的分配和釋放。我們在說數(shù)組的時(shí)候遇到過這樣的問題,本來我們的數(shù)組要放是個(gè)元素,但是后來需要向里面增加其他幾個(gè)元素,這時(shí)候,我們前面使用的基本數(shù)組類型的長度是不能變的,所以會出現(xiàn)不能儲存的問題,這時(shí)候怎么辦呢,于是就需要我們自己取申請一個(gè)可變長的的數(shù)組。靜態(tài)分配?不行,早早就給把內(nèi)存空間分配好了。棧?這也不行,我們在定義基本數(shù)據(jù)類型變量時(shí)已經(jīng)告訴數(shù)組長度,系統(tǒng)也給分配好了,還想變,不可能。那么我我們就只剩下堆了,堆是我們編程人員可以控制的一片區(qū)域空間,所以我想申請多大空間就可以申請多大空間,不過一般來說,在分配內(nèi)存的時(shí)候,我們不需要告訴計(jì)算機(jī)我們需要多大的內(nèi)存,畢竟在不同的操作系統(tǒng)上,一個(gè)數(shù)據(jù)類型的長度是不同的。需要注意的是,在我們分配了內(nèi)存后,就必須要將其釋放掉,否則數(shù)據(jù)會一直存在,直到程序結(jié)束,如果不釋放,內(nèi)存就會漸漸變滿,是不是就出現(xiàn)問題了,所以在內(nèi)存操作的時(shí)候一定要記住一個(gè)成語:“有始有終”。

通過上面的描述,我們是不是就可以看到這三種內(nèi)存分配模式的效率問題了。靜態(tài)內(nèi)存是在程序啟動時(shí)就已經(jīng)分配好了,程序在運(yùn)行過程中直接拿來用。棧是需要等待程序運(yùn)行時(shí)自動分配和釋放。但是堆的話,既不能在程序啟動時(shí)分配空間,又不能在程序運(yùn)行時(shí)提前分配空間,只能等待在需要的時(shí)候增加內(nèi)存或減少內(nèi)存。這樣看來,靜態(tài)內(nèi)存分配效率最快,然后是棧,最后才是堆。

鏈表

當(dāng)然,對只是內(nèi)存的分配,函數(shù)才是我們操作內(nèi)存的主要手段,在C語言中,能夠動態(tài)內(nèi)存分配的函數(shù)有malloc(常用),Calloc(分配連續(xù)的一塊內(nèi)存)、realloc(重新分配內(nèi)存大?。ree(釋放上面所申請的內(nèi)存),那么這些函數(shù)是怎么實(shí)現(xiàn)在堆上的內(nèi)存申請和釋放呢,首先,堆的內(nèi)存并不是連續(xù)不斷的,它在申請的時(shí)候會向系統(tǒng)申請一塊內(nèi)存空間,當(dāng)這片內(nèi)存空間用完后,它會向系統(tǒng)繼續(xù)申請另一塊空間,這時(shí)候系統(tǒng)會從低地址向高地址遍歷,如果出現(xiàn)大小合適的空閑空間,那么就會通過我們前面所說的指針進(jìn)行連接,這種方式是不是和鏈表一個(gè)道理,所以在學(xué)習(xí)C語言的時(shí)候,總是會提倡要求了解鏈表的概念和實(shí)現(xiàn)方式。當(dāng)然,這種方式是有弊端的,當(dāng)鏈表中指針被破壞時(shí),堆就會出現(xiàn)問題,被分開的內(nèi)存空間可能會被其他程序越界讀取和使用,而且長期對內(nèi)存進(jìn)行遍歷,數(shù)據(jù)小時(shí)還行,當(dāng)數(shù)據(jù)達(dá)到一定規(guī)模后,每次進(jìn)行遍歷,都需要消耗大量時(shí)間,所以就有了新的理論和觀點(diǎn),就是我們說的內(nèi)存池,內(nèi)存池主要講的并不是內(nèi)存的申請和分配問題,而是對自己內(nèi)存的管理,不過這個(gè)內(nèi)存池管理的原理比較復(fù)雜。我們前面說的ARC和MRC實(shí)際上就是對內(nèi)存池的管理,當(dāng)申請內(nèi)存空間時(shí),在池子中對這個(gè)對象進(jìn)行引用加一,這片內(nèi)存空間沒有任何引用時(shí),才正式釋放掉,這就是我們常說的“內(nèi)存垃圾回收機(jī)制”。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 內(nèi)存管理 簡述OC中內(nèi)存管理機(jī)制。與retain配對使用的方法是dealloc還是release,為什么?需要與a...
    丶逐漸閱讀 2,081評論 1 16
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,666評論 1 32
  • 為什么管理內(nèi)存: 程序在運(yùn)行的時(shí)候,要創(chuàng)建大量的對象,這些對象放在堆和棧上。(基本類型放在棧上,由系統(tǒng)自動管理。)...
    我是誰重要嗎閱讀 1,480評論 0 12
  • 幫師妹和一個(gè)球友牽線成功,他們一直想請我吃飯。我說,請我吃飯不如請我打球,請吃飯你浪費(fèi)錢財(cái)、我浪費(fèi)時(shí)間,但是那天我...
    考拉王的桉樹閱讀 540評論 0 1
  • 天地?zé)o絕,萬物無絕,絕境無絕,生生不息,不息生生。
    21xd閱讀 87評論 0 0

友情鏈接更多精彩內(nèi)容