淺談iOS中Block的內(nèi)存管理


一烈掠、前言:

?Block是Objective-C中的一項(xiàng)強(qiáng)大的特性抑淫,Block可以看作是OC中對(duì)于閉包函數(shù)的實(shí)現(xiàn)幻件,實(shí)質(zhì)上Block也是一個(gè)對(duì)象~


二会前、內(nèi)存分配區(qū)域:

OC中的各個(gè)主要的內(nèi)存分配區(qū)域:包括有--棧區(qū)好乐、堆區(qū)、常量區(qū)瓦宜、全局靜態(tài)區(qū)蔚万、文本區(qū)(代碼區(qū))


內(nèi)存分配區(qū)域

棧區(qū):存放函數(shù)參數(shù)值、局部變量临庇、函數(shù)返回地址等笛坦,我們每次調(diào)用函數(shù),都會(huì)執(zhí)行壓棧操作(在XCode的左側(cè)面板會(huì)看到一堆的函數(shù)調(diào)用棧)苔巨。特點(diǎn)是存取效率高版扩,存取結(jié)構(gòu)連續(xù),但是空間很小侄泽,有系統(tǒng)自行分配以及管理?xiàng)5牡刂房臻g礁芦。

堆區(qū):這個(gè)使我們開發(fā)者需要重點(diǎn)關(guān)注的內(nèi)存區(qū)域,因?yàn)槠綍r(shí)涉及到內(nèi)存管理基本上出自于這個(gè)區(qū)域。由malloc柿扣、alloc肖方、copy(深復(fù)制)、new等方法觸發(fā)的效果就是在堆區(qū)進(jìn)行內(nèi)存分配未状。在ARC的環(huán)境下俯画,系統(tǒng)幫助我們根據(jù)對(duì)象的引用計(jì)數(shù)去管理這個(gè)區(qū)域的內(nèi)存分配以及是釋放,但我們也要時(shí)刻注意該區(qū)域的內(nèi)存使用情況司草;而在MRC的環(huán)境下則需要開發(fā)者時(shí)時(shí)刻刻注意這個(gè)區(qū)域的內(nèi)存使用情況艰垂,否則后果你懂的~

靜態(tài)區(qū):該區(qū)域其實(shí)細(xì)分為數(shù)據(jù)區(qū)以及BSS區(qū)。數(shù)據(jù)區(qū)存放已經(jīng)初始化好的靜態(tài)變量以及全局變量埋虹,而BSS區(qū)則存放還沒(méi)有初始化好的靜態(tài)變量以及全局變量猜憎,由系統(tǒng)負(fù)責(zé)釋放以及分配。

常量區(qū):存放常量搔课,由系統(tǒng)釋放以及分配胰柑。

代碼區(qū) (文本區(qū)) :存放函數(shù)體代碼。


三爬泥、Block的三種分類:

全局區(qū)的Block:__NSGlobalBlock__柬讨;

棧區(qū)的Block:__NSStackBlock__;

堆區(qū)的Block:__NSMallocBlock__袍啡;

1姐浮、__NSGlobalBlock__:

當(dāng)我們聲明一個(gè)block時(shí),如果這個(gè)block沒(méi)有捕獲外部的變量葬馋,那么這個(gè)block就位于全局區(qū)卖鲤,此時(shí)對(duì)NSGlobalBlock的retain、copy畴嘶、release操作都無(wú)效蛋逾。ARC和MRC環(huán)境下都是如此。


如圖所示窗悯,聲明并且定義一個(gè)全局區(qū)的block

2区匣、__NSStackBlock__:

? 這里可能有人會(huì)問(wèn),平時(shí)編程的時(shí)候很少遇到位于棧區(qū)的block蒋院,為什么呢亏钩?因?yàn)樵贏RC環(huán)境下,當(dāng)我們聲明并且定義了一個(gè)block欺旧,并且沒(méi)有為Block添加額外的修飾符(默認(rèn)是__strong修飾符)姑丑,如果該Block捕獲了外部的變量,實(shí)質(zhì)上是有一個(gè)從__NSStackBlock__轉(zhuǎn)變到__NSMallocBlock__的過(guò)程辞友,只不過(guò)是系統(tǒng)幫我們完成了copy操作栅哀,將棧區(qū)的block遷移到堆區(qū)震肮,延長(zhǎng)了Block的生命周期。對(duì)于棧區(qū)block而言留拾,棧block在當(dāng)函數(shù)退出的時(shí)候戳晌,該空間就會(huì)被回收。

? ?那什么時(shí)候在ARC的環(huán)境下出現(xiàn)__NSStackBlock__呢痴柔?如果我們?cè)诼暶饕粋€(gè)block的時(shí)候沦偎,使用了__weak或者_(dá)_unsafe__unretained的修飾符,那么系統(tǒng)就不會(huì)為我們做copy的操作咳蔚,不會(huì)將其遷移到堆區(qū)豪嚎。下面我們實(shí)驗(yàn)一下:


如上圖所示,被__weak修飾的myBlock1捕獲了外部變量n屹篓,成為一個(gè)棧區(qū)的block


默認(rèn)修飾符環(huán)境下,捕獲了外部變量的block位于堆區(qū)

我們可以手動(dòng)地去執(zhí)行copy方法匙奴,驗(yàn)證系統(tǒng)為我們做的隱式轉(zhuǎn)換:


如圖所示堆巧,手動(dòng)執(zhí)行copy方法之后,block被遷移到了堆區(qū)

3泼菌、__NSMallocBlock__:

在MRC環(huán)境下谍肤,我們需要手動(dòng)調(diào)用copy方法才可以將block遷移到堆區(qū),而在ARC環(huán)境下哗伯,__strong修飾的(默認(rèn))block只要捕獲了外部變量就會(huì)位于堆區(qū)荒揣,NSMallocBlock支持retain、release焊刹,會(huì)對(duì)其引用計(jì)數(shù)+1或 -1系任。聲明以及定義位于堆區(qū)的block如上圖所示。


四虐块、block對(duì)不同類型的外部變量的存攘├摹:

1、眾所周知贺奠,對(duì)于block捕獲的外部變量霜旧,block 默認(rèn)是將其復(fù)制到其數(shù)據(jù)結(jié)構(gòu)中來(lái)實(shí)現(xiàn)訪問(wèn)的,因此儡率,對(duì)于捕獲的普通的外部變量挂据,block并不能作出修改。我們要改變外部變量的內(nèi)存地址儿普,也就是使用__block修飾符將外部變量在棧中指針的內(nèi)存地址崎逃,遷移到堆區(qū)中來(lái)。為什么要這樣設(shè)計(jì)呢眉孩,我們引用@ChenYiLong的一句話:

Apple這樣設(shè)計(jì)婚脱,應(yīng)該是考慮到了block的特殊性,block也屬于“函數(shù)”的范疇,變量進(jìn)入block障贸,實(shí)際就是已經(jīng)改變了作用域错森。在幾個(gè)作用域之間進(jìn)行切換時(shí),如果不加上這樣的限制篮洁,變量的可維護(hù)性將大大降低涩维。又比如我想在block內(nèi)聲明了一個(gè)與外部同名的變量,此時(shí)是允許呢還是不允許呢袁波?只有加上了這樣的限制瓦阐,這樣的情景才能實(shí)現(xiàn)。于是棧區(qū)變成了紅燈區(qū)篷牌,堆區(qū)變成了綠燈區(qū)睡蟋。

因此,__block修飾符的根本操作就是改變外部變量的內(nèi)存地址枷颊,并不是簡(jiǎn)單地使得寫操作生效戳杀。

2、此外夭苗,如果將block捕獲的外部變量使用static修飾或者將外部變量聲明為全局變量信卡,那么block是可以直接修改該外部變量的,因?yàn)槿肿兞炕蜢o態(tài)變量在內(nèi)存中的地址是固定的(存放于上文中的靜態(tài)區(qū))题造,Block在讀取該變量值的時(shí)候是直接從其所在內(nèi)存讀出傍菇,獲取到的是最新值,而不是在定義時(shí)copy的常量界赔。


如上圖所示丢习,捕獲了靜態(tài)變量以及全局變量的block可以直接修改它們的值,要注意的是淮悼,雖然此時(shí)block捕獲了外部變量泛领,但是仍然是位于全局區(qū)的block。


下一篇文章我們一起來(lái)看看block的底層數(shù)據(jù)結(jié)構(gòu)敛惊,以及它如何實(shí)現(xiàn)捕獲變量的操作~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末渊鞋,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瞧挤,更是在濱河造成了極大的恐慌锡宋,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件特恬,死亡現(xiàn)場(chǎng)離奇詭異执俩,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)癌刽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門役首,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)尝丐,“玉大人,你說(shuō)我怎么就攤上這事衡奥〉” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵矮固,是天一觀的道長(zhǎng)失息。 經(jīng)常有香客問(wèn)我,道長(zhǎng)档址,這世上最難降的妖魔是什么盹兢? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮守伸,結(jié)果婚禮上绎秒,老公的妹妹穿的比我還像新娘。我一直安慰自己尼摹,他們只是感情好见芹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著窘问,像睡著了一般辆童。 火紅的嫁衣襯著肌膚如雪宜咒。 梳的紋絲不亂的頭發(fā)上惠赫,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音故黑,去河邊找鬼儿咱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛场晶,可吹牛的內(nèi)容都是我干的混埠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼诗轻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼钳宪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起扳炬,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤吏颖,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后恨樟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體半醉,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年劝术,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缩多。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呆奕。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖衬吆,靈堂內(nèi)的尸體忽然破棺而出梁钾,到底是詐尸還是另有隱情,我是刑警寧澤咆槽,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布陈轿,位于F島的核電站,受9級(jí)特大地震影響秦忿,放射性物質(zhì)發(fā)生泄漏麦射。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一灯谣、第九天 我趴在偏房一處隱蔽的房頂上張望潜秋。 院中可真熱鬧,春花似錦胎许、人聲如沸峻呛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)钩述。三九已至,卻和暖如春穆碎,著一層夾襖步出監(jiān)牢的瞬間牙勘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工所禀, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留方面,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓色徘,卻偏偏與公主長(zhǎng)得像恭金,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子褂策,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容