iOS 內(nèi)存管理

內(nèi)存分配

  • 棧 stack
    • 由系統(tǒng)管理溶褪,分配和釋放
    • 存儲局部變量,保存函數(shù)現(xiàn)場
    • 連續(xù)的內(nèi)存地址辨图,由高向低分配班套,不會產(chǎn)生碎片
    • 效率高。棧是機器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu)徒役,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址孽尽,壓棧出棧都有專門的指令執(zhí)行窖壕,這就決定了棧的效率比較高忧勿。
    • 類似于數(shù)據(jù)結(jié)構(gòu)中的棧杉女,先進后出

    每一個方法執(zhí)行的時候都會向棧區(qū)申請內(nèi)存,這部分內(nèi)存隨著方法的結(jié)束而釋放鸳吸,由系統(tǒng)自動分配熏挎。棧區(qū)的大小是事先規(guī)定好的(2M / 1M),如果申請的空間超過剩余可用空間就會發(fā)生 stackoverflow晌砾。

  • 堆 heap
    • 開發(fā)者手動管理 alloc release
    • 不連續(xù)的內(nèi)存地址坎拐,由低向高分配,容易產(chǎn)生碎片
    • 分配方式類似鏈表养匈,先進先出
    • 效率不如棧哼勇。計算機底層并沒有對堆的支持,堆是有 C/C++ 函數(shù)庫提供的呕乎,加上碎片問題积担,導致堆的效率比棧低。

    系統(tǒng)會有個記錄空閑地址的鏈表猬仁,當系統(tǒng)收到內(nèi)存申請的時候帝璧,就去遍歷該鏈表,尋找第一個空間大于申請空間的堆結(jié)點湿刽,然后將該結(jié)點刪除的烁,并將該結(jié)點的空間分配給程序。如果分配的空間有多余诈闺,系統(tǒng)將會把多余的空間重新放回鏈表中渴庆。雖然程序結(jié)束后,所以的數(shù)據(jù)空間都會被系統(tǒng)回收雅镊,但是精確的申請與釋放內(nèi)存是我們必備的素質(zhì)把曼。

  • 全局區(qū) / 靜態(tài)區(qū)
    • 存儲全局變量、靜態(tài)變量
    • bbs:未初始化漓穿;data:初始化的
  • 常量區(qū)
    • 常量字符串
  • 代碼區(qū)
    • 存儲 App 二進制代碼

ARC 與 MRC

對象操作

  • alloc/new/copy/mutableCopy 生成并持有對象嗤军,retainCount: +1
  • retain 持有對象,retainCount: +1
  • release 釋放對象晃危,retainCount: -1
  • dealloc 廢棄對象

內(nèi)存管理基本規(guī)則

  • 生成并持有對象
  • 持有非自己生成的對象
  • 不再需要自己持有對象的時候釋放
  • 非自己持有的對象無法釋放

ARC 原理

ARC 是蘋果在 LLVM 3.0 開始引用一種內(nèi)存管理機制叙赚,會根據(jù)對象的引用計數(shù)自動監(jiān)控對象的生命周期,實現(xiàn)方式是在編譯時期自動在已有的代碼中插入合適的內(nèi)存管理代碼以及在 Runtime 做一些優(yōu)化僚饭。

所有權(quán)修飾符

ARC 規(guī)定每個對象前必須加上所有權(quán)修飾符:

  • __strong
    默認的所有權(quán)修飾符震叮,表示對對象的強引用,持有強引用的對象在超過其作用域時被廢棄
// ARC 無效
{
    id obj = [[NSObject alloc] init];
    [obj release];
}

// ARC 有效
{
    id __strong obj = [[NSObject alloc] init];
}
  • __weak
    表示對對象的弱引用鳍鸵,主要用于避免循環(huán)引用苇瓣,如果對象沒有強引用了,弱引用會被置為 nil
  • __unsafe_unretained
    不安全所有權(quán)修飾符偿乖,同 __weak 作用一樣击罪,只是在對象沒有強引用的時候不會被置為 nil抽诉,該指針就變成了懸垂指針
  • __autorelesing
    用于替代 autorelease 方法
屬性修飾符

賦值性

  • strong 強引用虐块,先保留新值骏全,再釋放舊值网持,最后賦值
- (void)setValue:(id)newValue {
    [newValue retain];
    [_value release];
    _value = newValue;
}
  • retain 在 ARC 下與 strong 類似,MRC 下修飾 block 時竣稽,strong 會把 block 拷貝到堆區(qū)囱怕,retain 不會
  • weak 弱引用,既不保留新值也不釋放舊值毫别,當對象被釋放時娃弓,自動指向 nil
  • unsafe_unretained 與 weak 一樣,只是當對象被釋放時岛宦,不會自動指向 nil
  • assign 賦值操作忘闻,通常用于基本數(shù)值類型,不涉及應用計數(shù)恋博,默認屬性
  • copy 類似于 strong齐佳,不過在賦值的時候進行的是 copy 而不是 retain 操作,一般用于修飾不可變對象( NSString )和 block

讀寫性

  • readonly 只讀特性债沮,只生成 getter 方法
  • readwrite 可讀可寫特性炼吴,生成 settergetter 方法疫衩,默認屬性

原子性

  • nonatomic 非原子特性硅蹦,不加同步,多線程訪問時效率高闷煤,但是線程不安全童芹,settergetter 不是原子操作
  • atomic 原子特性鲤拿,同步操作假褪,多線程安全(不是絕對,因為)近顷,setter生音、getter 是原子操作,默認屬性

指定方法名

  • getter = <getMethodName>窒升,setter = <setMethodName>
相關問題

NSString 為什么要用 copy 修飾缀遍?
NSMutableString 是 NSString 的子類,所以可以把一個 NSMutableString 賦值給 NSString饱须,這樣就不能保證 NSString 不可變性了域醇,所以最好使用 copy 修飾,這樣賦值的時候就會先拷貝新值然后賦值,不管可變不可變都會變成不可變字符串譬挚。

block 為什么要用 copy 修飾锅铅?
在 MRC 環(huán)境下時,block 默認是放在棧里面的殴瘦,所以要用 copy 修飾狠角,將其拷貝到堆區(qū)号杠,避免釋放蚪腋。而在 ARC 環(huán)境下,用 storng 修飾姨蟋,系統(tǒng)也會自動將其拷貝到堆區(qū)屉凯,所以用 strong 和 copy 修飾都是可行的,但是蘋果建議我們用 copy 修飾眼溶,這樣能顯式地指明內(nèi)存行為悠砚,官方文檔描述如下:

Note: You should specify copy as the property attribute, because a block needs to be copied to keep track of its captured state outside of the original scope. This isn’t something you need to worry about when using Automatic Reference Counting, as it will happen automatically, but it’s best practice for the property attribute to show the resultant behavior.

atomic 為什么不是一定線程安全的?
atomic 只是表明該屬性的 setter堂飞、getter 是線程安全的。

ARC 優(yōu)點

  • 減少工作量绰筛,無需鍵入 retain 或者 release 代碼
  • 降低程序崩潰、內(nèi)存泄漏等風險
  • 編譯器完全清楚目標對象铝噩,并能立即釋放那些不再被使用的對象衡蚂,這樣應用程序就具有可預測性骏庸,且能流暢運行,速度也將大幅提升

不要使用 retainCount

retainCount 在實際的 release 環(huán)境中是沒有什么作用的具被,在 debug 的時候,retainCount 返回的數(shù)值也不一定準確一姿,因為系統(tǒng)會對 retainCount 進行優(yōu)化补箍,比如當一個對象的 retainCount 為 1 的時候啸蜜,再對它進行 release 操作,系統(tǒng)可能只是標記該內(nèi)存可回收衬横,沒必要再繼續(xù)一次 -1 的數(shù)值操作,這個時候返回的 retainCount 就不會為 0。而且對于加入自動釋放池的對象遥诉,對其發(fā)送 retainCount 消息是一件很危險的事情,因為無法確定其是否被釋放矮锈,或者內(nèi)存是否被復用,如果被其他對象復用苞笨,返回的 retainCount 必然是有問題的债朵。

循環(huán)引用

  • 主動釋放
  • 弱引用
    • weak 可以為空
    • unowned 不能為空

相關閱讀

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末序芦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子粤咪,更是在濱河造成了極大的恐慌谚中,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寥枝,死亡現(xiàn)場離奇詭異宪塔,居然都是意外死亡,警方通過查閱死者的電腦和手機囊拜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門某筐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人艾疟,你說我怎么就攤上這事来吩。” “怎么了蔽莱?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵弟疆,是天一觀的道長。 經(jīng)常有香客問我盗冷,道長怠苔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任仪糖,我火速辦了婚禮柑司,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锅劝。我一直安慰自己攒驰,他們只是感情好,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布故爵。 她就那樣靜靜地躺著玻粪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上劲室,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天伦仍,我揣著相機與錄音,去河邊找鬼很洋。 笑死充蓝,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的喉磁。 我是一名探鬼主播谓苟,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼线定!你這毒婦竟也來了娜谊?” 一聲冷哼從身側(cè)響起确买,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤斤讥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后湾趾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芭商,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年铛楣,在試婚紗的時候發(fā)現(xiàn)自己被綠了艺普。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡歧譬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出矢洲,到底是詐尸還是另有隱情,我是刑警寧澤读虏,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布盖桥,位于F島的核電站,受9級特大地震影響揩徊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜靴拱,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一袜炕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧偎窘,春花似錦、人聲如沸他托。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沿盅。三九已至,卻和暖如春韧掩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疗锐。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工费彼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人敌买。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像聋庵,于是被迫代替她去往敵國和親芙粱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

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