棧區是先進后出,隊列是先進先出。
棧區就相當于玻璃杯,往玻璃杯里放奧利奧,第一塊放入的奧利奧,肯定是最后一個拿出來。
隊列就相當于掉了底的玻璃杯,最先放入的,必定最先掉出來。
網上有個更絕的比喻:隊列是吃多了拉,棧區是吃多了吐。
這里解析的是棧區和堆區的內存問題,說到了棧區自然引出隊列,捎帶提一筆。
言歸正傳,以下面這個非常簡單的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類型,在編譯的時候也不會報錯,會有警告
這就說明:堆中開辟的內存自身并不強調類型,而是受到棧區中對象類型的左右。