OC中棧區與堆區的記憶體概念解析

2022-08-09 01:27:20 字數 1964 閱讀 2937

棧區是先進後出,佇列是先進先出。

棧區就相當於玻璃杯,往玻璃杯裡放奧利奧,第一塊放入的奧利奧,肯定是最後乙個拿出來。

佇列就相當於掉了底的玻璃杯,最先放入的,必定最先掉出來。

網上有個更絕的比喻:佇列是吃多了拉,棧區是吃多了吐。

這裡解析的是棧區和堆區的記憶體問題,說到了棧區自然引出佇列,捎帶提一筆。

言歸正傳,以下面這個非常簡單的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 申請大小 能從棧獲得的空間較小,堆是向高位址擴充套件的資料結構,是不連續的記憶體區域。堆的大小受限於計算機系統中有效的虛...