棧區是先進後出,佇列是先進先出。
棧區就相當於玻璃杯,往玻璃杯裡放奧利奧,第一塊放入的奧利奧,肯定是最後乙個拿出來。
佇列就相當於掉了底的玻璃杯,最先放入的,必定最先掉出來。
網上有個更絕的比喻:佇列是吃多了拉,棧區是吃多了吐。
這裡解析的是棧區和堆區的記憶體問題,說到了棧區自然引出佇列,捎帶提一筆。
言歸正傳,以下面這個非常簡單的c語言程式為例:
變數 i 和 j 就是儲存在棧區里的
有一句話如是說:在oc中,預設不帶*號的都是儲存在棧區的。
在這裡,變數名其實就是變數儲存在棧區的記憶體位址的別名。
那麼,這個程式執行時在棧區是如何出入的呢?
程式在棧區的出入步驟:
程式執行執行main函式,i首先進入棧區,位於最底部。然後j進入棧區,printf呼叫函式sum(i, j)緊隨其後進入棧區。
函式sum(int x, int y)中的引數,從右到左依次進入棧區。先是y再是x。
棧區儲存樣式
當程式執行結束後,棧區內的所有元素會從上到下的依次出棧,棧會恢復到原始狀態。
棧的先進後出方式,會特別整齊的訪問,不會產生記憶體碎片。
現在加入執行緒概念:每條主線程為1m記憶體,每條子執行緒為512k記憶體
每個執行緒都會對應乙個棧區!
當程式開展了多條執行緒的時候,每個執行緒都會開闢一塊棧區,如下圖所示:
當執行緒執行完畢之後,各個執行緒棧區會依次清除掉。
所以:對於系統來說,給執行緒分配棧區記憶體只需要分配512kb的倍數即可,
分配出來的這塊記憶體空間作為多執行緒整體的棧區,來管理多執行緒。
如此一來,記憶體會被管理的井井有條,速度飛快。
堆區堆區是由系統通過鍊錶管理維護的,所有應用程式共享的一塊記憶體空間。包括記憶體+虛擬記憶體(磁碟快取)
程式執行時堆區的內部操作,以及引發記憶體洩漏的原因:
建立乙個新的物件時,物件p指標存放在棧區,p將指向在堆區開闢的一塊儲存空間person
在程式結束之前,p物件必須release,不然系統不知道釋放堆區的person記憶體。
如果p物件沒有release,只是p=nil; 就是p指標指向了堆區位址為0的地方,那麼原來的person永遠無法再次訪問,而且也無法釋放掉。
堆是所有程式共享的記憶體,當n個這樣的記憶體得不到釋放,堆區會被擠爆,程式立馬癱瘓。這就是記憶體洩漏。
這裡要知道的是:系統在堆區只會記錄某乙個區域被使用了,並不會管你是什麼型別的(匿名訪問)。
我寫了一段物件與堆區的對話,來說明這個現象:
某程式的物件p:喂!堆!我有個person,你給我記錄一下。
堆:尼瑪,今天我碰到了n個person了,別瞎掰活,直接說要多大空間!
p:100kb
堆:已開闢。
堆就跟小旅館一樣,我管你是男女老幼,直接說要什麼價位的房子。
那麼,既然是匿名訪問,堆不管你的型別了,那怎麼區分這塊記憶體是什麼型別的呢?
簡單:什麼型別指向這塊記憶體,這塊記憶體就是什麼型別的。
程式示例:
定義乙個person類
在main.m檔案中利用person類建立乙個物件,這個物件即便是定義為nsstring型別,在編譯的時候也不會報錯,會有警告
這就說明:堆中開闢的記憶體自身並不強調型別,而是受到棧區中物件型別的左右。
OC中棧區與堆區的記憶體概念解析
棧區是先進後出,佇列是先進先出。棧區就相當於玻璃杯,往玻璃杯裡放奧利奧,第一塊放入的奧利奧,肯定是最後乙個拿出來。佇列就相當於掉了底的玻璃杯,最先放入的,必定最先掉出來。網上有個更絕的比喻 佇列是吃多了拉,棧區是吃多了吐。這裡解析的是棧區和堆區的記憶體問題,說到了棧區自然引出佇列,捎帶提一筆。言歸正...
棧區,堆區,全域性區等概念
1 棧區 stack 由編譯器自動分配釋放 存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。2 堆區 heap 一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os 注意它與資料結構中的堆是兩回事,分配方式倒是類似於鍊錶,呵呵。3 全域性區 靜態區 static 全...
記憶體中堆區和棧區的區別
從下面五個方面說一下記憶體中堆和棧的區別 1 管理方式 對於棧來講,是由編譯器自動管理,無需我們手工控制 對於堆來說,釋放工作由程式設計師控制,容易產生memory leak。2 申請大小 能從棧獲得的空間較小,堆是向高位址擴充套件的資料結構,是不連續的記憶體區域。堆的大小受限於計算機系統中有效的虛...