棧區(qū)是先進后出贯溅,隊列是先進先出。
棧區(qū)就相當于玻璃杯躲查,往玻璃杯里放奧利奧它浅,第一塊放入的奧利奧,肯定是最后一個拿出來镣煮。
隊列就相當于掉了底的玻璃杯姐霍,最先放入的,必定最先掉出來典唇。
網(wǎng)上有個更絕的比喻:隊列是吃多了拉镊折,棧區(qū)是吃多了吐。
這里解析的是棧區(qū)和堆區(qū)的內(nèi)存問題蚓聘,說到了棧區(qū)自然引出隊列腌乡,捎帶提一筆。
言歸正傳夜牡,以下面這個非常簡單的c語言程序為例:
變量 i 和 j 就是保存在棧區(qū)里的
有一句話如是說:在OC中,默認不帶*號的都是保存在棧區(qū)的侣签。
在這里塘装,變量名其實就是變量保存在棧區(qū)的內(nèi)存地址的別名。
那么影所,這個程序運行時在棧區(qū)是如何出入的呢蹦肴?
程序在棧區(qū)的出入步驟:
程序運行執(zhí)行main函數(shù),i首先進入棧區(qū)猴娩,位于最底部阴幌。然后j進入棧區(qū),printf調(diào)用函數(shù)sum(i, j)緊隨其后進入棧區(qū)卷中。
函數(shù)sum(int x, int y)中的參數(shù)矛双,從右到左依次進入棧區(qū)。先是y再是x蟆豫。
棧區(qū)存儲樣式:
當程序運行結(jié)束后议忽,棧區(qū)內(nèi)的所有元素會從上到下的依次出棧,棧會恢復到原始狀態(tài)十减。
棧的先進后出方式栈幸,會特別整齊的存取愤估,不會產(chǎn)生內(nèi)存碎片。
現(xiàn)在加入線程概念:每條主線程為1M內(nèi)存速址,每條子線程為512K內(nèi)存
每個線程都會對應一個棧區(qū)玩焰!
當程序開展了多條線程的時候,每個線程都會開辟一塊棧區(qū)芍锚,如下圖所示:
當線程執(zhí)行完畢之后震捣,各個線程棧區(qū)會依次清除掉。
所以:對于系統(tǒng)來說闹炉,給線程分配棧區(qū)內(nèi)存只需要分配512kb的倍數(shù)即可蒿赢,
分配出來的這塊內(nèi)存空間作為多線程整體的棧區(qū),來管理多線程渣触。
如此一來羡棵,內(nèi)存會被管理的井井有條,速度飛快嗅钻。
堆區(qū)
堆區(qū)是由系統(tǒng)通過鏈表管理維護的皂冰,所有應用程序共享的一塊內(nèi)存空間。包括內(nèi)存+虛擬內(nèi)存(磁盤緩存)
程序運行時堆區(qū)的內(nèi)部操作养篓,以及引發(fā)內(nèi)存泄漏的原因:
創(chuàng)建一個新的對象時秃流,對象p指針存放在棧區(qū),p將指向在堆區(qū)開辟的一塊存儲空間Person
在程序結(jié)束之前柳弄,p對象必須release舶胀,不然系統(tǒng)不知道釋放堆區(qū)的Person內(nèi)存。
如果p對象沒有release碧注,只是p=nil; 就是p指針指向了堆區(qū)地址為0的地方嚣伐,那么原來的Person永遠無法再次訪問,而且也無法釋放掉萍丐。
堆是所有程序共享的內(nèi)存轩端,當N個這樣的內(nèi)存得不到釋放,堆區(qū)會被擠爆逝变,程序立馬癱瘓基茵。這就是內(nèi)存泄漏。
這里要知道的是:系統(tǒng)在堆區(qū)只會記錄某一個區(qū)域被使用了壳影,并不會管你是什么類型的(匿名訪問)拱层。
我寫了一段對象與堆區(qū)的對話,來說明這個現(xiàn)象:
某程序的對象p:喂态贤!堆舱呻!我有個Person,你給我記錄一下。
堆:尼瑪箱吕,今天我碰到了N個Person了芥驳,別瞎掰活,直接說要多大空間茬高!
p:100kb
堆:已開辟兆旬。
堆就跟小旅館一樣,我管你是男女老幼怎栽,直接說要什么價位的房子丽猬。
那么,既然是匿名訪問熏瞄,堆不管你的類型了脚祟,那怎么區(qū)分這塊內(nèi)存是什么類型的呢?
簡單:什么類型指向這塊內(nèi)存强饮,這塊內(nèi)存就是什么類型的由桌。
程序示例:
定義一個Person類
在main.m文件中利用Person類創(chuàng)建一個對象,這個對象即便是定義為NSString類型邮丰,在編譯的時候也不會報錯行您,會有警告
這就說明:堆中開辟的內(nèi)存自身并不強調(diào)類型,而是受到棧區(qū)中對象類型的左右剪廉。