iOS內(nèi)存管理機(jī)制及屬性的使用

對(duì)于OC的使用者來(lái)說(shuō),最會(huì)被問(wèn)到的就是iOS開(kāi)發(fā)中的內(nèi)存管理摊欠。而只要涉及到內(nèi)存管理丢烘,就肯定會(huì)涉及到property。而且在平常iOS開(kāi)發(fā)的面試中些椒,我們也經(jīng)常會(huì)被問(wèn)到相關(guān)的問(wèn)題播瞳。所以這次就結(jié)合我所見(jiàn)到的和自己對(duì)于屬性的理解來(lái)進(jìn)行簡(jiǎn)述,希望對(duì)你們有幫助免糕。

在講述屬性前赢乓,我們需要對(duì)于iOS開(kāi)發(fā)中的內(nèi)存管理有一個(gè)初步的了解忧侧。

本文中的部分內(nèi)容來(lái)源于:這里這里還有部分來(lái)源于蘋果官方文檔。

iOS開(kāi)發(fā)中的內(nèi)存使用情況

  • 棧(stack):棧是編譯器自動(dòng)分配并釋放骏全,用來(lái)存放函數(shù)的參數(shù)苍柏,局部變量。
  • 堆(heap):堆一般是程序員自己分配和釋放姜贡,如果我們?cè)谑褂玫倪^(guò)程中试吁,沒(méi)有釋放,那么等到程序完全結(jié)束楼咳,系統(tǒng)將會(huì)對(duì)堆中的內(nèi)容進(jìn)行回收熄捍。一般開(kāi)發(fā)中的alloc就是存放在堆中的
  • 全局變量(靜態(tài)變量)(static):全局變量和靜態(tài)變量是單獨(dú)存放的,因?yàn)樗麄兊穆暶髦芷诤驼麄€(gè)程序的生命周期一致母怜。釋放的時(shí)間是由整個(gè)程序結(jié)束后系統(tǒng)負(fù)責(zé)回收余耽。
  • 文字常量區(qū):一般用來(lái)存放常量字符串,比如說(shuō)String *str = @"hello world",他的釋放也和全局變量一致苹熏,在程序結(jié)束后進(jìn)行釋放碟贾。
  • 程序代碼區(qū):用來(lái)存放函數(shù)的二進(jìn)制內(nèi)容的區(qū)域。

他們之間的在內(nèi)存中存放的關(guān)系如下圖所示:

內(nèi)存管理

而在日常開(kāi)發(fā)過(guò)程中轨域,我們所遇到最多的也是最容易問(wèn)到的就是袱耽,可能有的人對(duì)于這兩者還是很模糊,所以我再引用之前看到過(guò)的一段話來(lái)解釋(由于很久以前看到了干发,已經(jīng)忘記了出處朱巨,如果有人能夠告訴我,我一定加上):

內(nèi)管管理就像做菜枉长,而棧(stack)的使用就像我們下館子冀续,我們只要去酒店,告訴老板我們要什么必峰,他們就會(huì)幫我們準(zhǔn)備好洪唐,我們只要吃完付錢,就可以了吼蚁,也不用去管理那些之后的瑣事桐罕。而堆(heap)就像我們自己做菜,什么東西都得自己買好桂敛,做什么功炮,怎么做都得提前想好。做完之后還需要自己收拾最后的垃圾术唬。一般我們alloc一個(gè)對(duì)象薪伏,該對(duì)象的內(nèi)存就會(huì)被分配到堆上,而非對(duì)象創(chuàng)建的時(shí)候就會(huì)放到棧上粗仓,由系統(tǒng)在不需要的時(shí)候進(jìn)行回收嫁怀。

iOS內(nèi)存管理機(jī)制

當(dāng)你創(chuàng)建的對(duì)象的時(shí)候设捐,你總得需要告訴操作系統(tǒng),你將要在什么時(shí)候?qū)φ加羞@塊內(nèi)存的對(duì)象進(jìn)行釋放塘淑,就像平常生活中萝招,你怎么才能確定這房間里面是有人的還是沒(méi)有人的呢?

一般來(lái)說(shuō)存捺,我們肯定會(huì)這么干槐沼,每個(gè)人進(jìn)去的時(shí)候登記下,然后出來(lái)的時(shí)候再登記下捌治,這樣只要我們?cè)谛枰芾淼臅r(shí)候看下登記再按的人數(shù)是不是為0就可以了岗钩,只要為0,那么就說(shuō)明里面沒(méi)有人肖油,否則就有人兼吓,蘋果也是這么處理內(nèi)存管理的。在你創(chuàng)建一個(gè)對(duì)象的時(shí)候森枪,他會(huì)需要進(jìn)行retain视搏,然后在你不在持有他的時(shí)候進(jìn)行release,所以每個(gè)對(duì)象都有一個(gè)retain count來(lái)進(jìn)行計(jì)數(shù)县袱。

在iOS中有2套內(nèi)存管理機(jī)制:MRC(MannulReference Counting)和ARC(Automatic Reference Counting)凶朗。其中ARC起源于iOS 4.3,在那之前显拳,蘋果開(kāi)發(fā)者只能手動(dòng)使用retainrelease來(lái)進(jìn)行內(nèi)存管理。這樣做的問(wèn)題很明顯搓萧,如果你在開(kāi)發(fā)過(guò)程中杂数,一個(gè)不小心沒(méi)有retainrelease成對(duì)出現(xiàn),那么很容易使得內(nèi)存沒(méi)有釋放瘸洛,最后導(dǎo)致程序內(nèi)存不足而導(dǎo)致閃退揍移。

對(duì)于ARC,蘋果的官方文檔是這么解釋的:

Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects. Rather than having to think about retain and release operations, ARC allows you to concentrate on the interesting code, the object graphs, and the relationships between objects in your application.

ARC works by adding code at compile time to ensure that objects live as long as necessary, but no longer. Conceptually, it follows the same memory management conventions as manual reference counting (described in Advanced Memory Management Programming Guide) by adding the appropriate memory management calls for you.

總的來(lái)說(shuō)反肋,主要意思就是ARC在本質(zhì)上就像MRC一樣那伐,但是它能夠讓你花費(fèi)更少的時(shí)間來(lái)考慮代碼中的retainrelease。與此同時(shí)石蔗,編譯器能夠幫你更加準(zhǔn)確的將retainrelease加在你代碼中真正需要的地方罕邀。

理解如下圖:


ARC && MRC
ARC && MRC

有人可能會(huì)提到GC(Garbage Collection)——垃圾回收機(jī)制。在現(xiàn)在的iOS中GC沒(méi)有被使用养距,而在MAC OS X中诉探,GC是被使用的,不過(guò)對(duì)于GC棍厌,蘋果是這么解釋的:

Garbage collection is deprecated in OS X Mountain Lion v10.8, and will be removed in a future version of OS X. Automatic Reference Counting is the recommended replacement technology. To aid in migrating existing applications, the ARC migration tool in Xcode 4.3 and later supports migration of garbage collected OS X applications to ARC

總的來(lái)說(shuō)ARC將在未來(lái)的某一天來(lái)取代GC在MAC中的位置肾胯。

property(屬性)

就算理解的再多竖席,我們還是要和實(shí)際相結(jié)合。實(shí)際運(yùn)用中與之相對(duì)應(yīng)的就是實(shí)例變量的屬性敬肚。
由于 iOS 中 MRC已經(jīng)太過(guò)于古老毕荐,在這就不再多提。

在ARC中艳馒,我們創(chuàng)建實(shí)例變量經(jīng)常是這樣的

@property (atomic/nonatomic/assign/retain/strong/weak/unsafe_unretained/copy) Number* num

所以我們就為讓這內(nèi)容中的這幾個(gè)property來(lái)進(jìn)行解釋憎亚。

  • atomic:原子性,簡(jiǎn)單的解釋就是說(shuō)鹰溜,他是線程安全的虽填,但是由于線程安全,在操作的過(guò)程中曹动,編譯器會(huì)自己給他上鎖斋日,解鎖。這樣會(huì)造成資源的浪費(fèi)(因?yàn)槲覀兤匠i_(kāi)發(fā)中不會(huì)那么頻繁的考慮到線程安全這個(gè)問(wèn)題)該屬性為默認(rèn)值
  • nonatomic:非原子性墓陈,這個(gè)和上面那個(gè)是雙子星恶守,但是他們正好相反,這個(gè)由于不安全的贡必,但是因?yàn)闆](méi)有了鎖的問(wèn)題兔港,這樣資源就會(huì)盡可能的被利用,所以我們?cè)谌粘i_(kāi)發(fā)中使用這個(gè)仔拟,而對(duì)于他的安全性衫樊,我們一般都自己在后期開(kāi)發(fā)的過(guò)程中,在使用多線程的過(guò)程中進(jìn)行考慮利花。
  • assign:給予了setter方法科侈,assign一般指向一個(gè)不是指針指向的對(duì)象,比如說(shuō)CGFloat這類值炒事。(關(guān)于assignweak在delegate中的區(qū)別將會(huì)在后面提到)
  • retain:retain用于指向一個(gè)有指針的對(duì)象臀栈,就像MRC中的retain,他是為了增加retain count挠乳,這樣使得對(duì)象能夠在autoreleasepool中持有內(nèi)存
  • strong:strong是在ARC中用來(lái)代替retain的权薯,所以原理相同,即retain count加一
  • weak:weakstrong一般只要懂一點(diǎn)英語(yǔ)的就知道睡扬,他們又是一堆雙子星盟蚣,strong是表示持有,而weak表示卖怜,只是簡(jiǎn)單的引用刁俭。這意味著等到持有weak的對(duì)象唄釋放的時(shí)候,weak表示的對(duì)象也被釋放韧涨。而需要注意的是weak釋放后他就會(huì)為nil牍戚。
  • unsafe_unretained:unsafe_unretained一般很少被用到侮繁,主要的原因是他一般用于在Cocoa底層的那些不能支持weak屬性的變量,比如說(shuō)NSTextView如孝,NSFont 宪哩,NSColorSpace等。而他和weak不同的地方是第晰,持有weak的對(duì)象被釋放后锁孟,weak對(duì)象會(huì)被指向nil,而unsafe_unretained則不會(huì)被指向?yàn)閚il茁瘦。這樣就有了安全隱患品抽。
  • copy:copy一般我們用在NSStringNSArray甜熔,NSDictionary圆恤,而原因就是copy會(huì)在復(fù)制的時(shí)候講源對(duì)象進(jìn)行拷貝。這樣他只想的將會(huì)是一個(gè)新的腔稀,retain count為1的對(duì)象盆昙。這樣在我們對(duì)于這個(gè)對(duì)象的內(nèi)容進(jìn)行修改的時(shí)候,它將不會(huì)影響到原來(lái)的那個(gè)對(duì)象焊虏。

除了這幾種之外淡喜,我們還有4種屬性沒(méi)有提到

  • getter:設(shè)置getter方法
  • setter:設(shè)置setter方法
  • readonly:只讀
  • readwrite:可讀寫

這四種因?yàn)榭梢愿鶕?jù)字面意思來(lái)進(jìn)行設(shè)置在這就不進(jìn)行過(guò)多的介紹。

這里再補(bǔ)上一句之前提到的問(wèn)題:

關(guān)于為什么使用weak而不是用assign來(lái)對(duì)delegate進(jìn)行標(biāo)注诵闭。

首先delegate一般的類型都是id炼团,即可以指向所有對(duì)象的id類型。所以我們既可以使用assign指向他疏尿,也可以使用weak指向他瘟芝。但是因?yàn)閣eak在不被持有的時(shí)候會(huì)指向nil,而大家都知道润歉,所有通過(guò)nil的方法在調(diào)用函數(shù)的時(shí)候,都會(huì)返回為nil颈抚,這樣就能夠保證了程序的穩(wěn)定性踩衩,就算沒(méi)有東西返回,他還是能夠正常解析(只是解析出來(lái)的值為nil)贩汉。而如果使用assign的話驱富,如果一不持有他。那么下次再調(diào)用它的時(shí)候匹舞,他將會(huì)指向一個(gè)不知名的地址褐鸥,即野指針。這樣就會(huì)使得整個(gè)程序crash赐稽。

autoreleasepool(自動(dòng)釋放池)

既然扯到release叫榕,那就不得不提下autoreleasepool浑侥,顧名思義,他就是一個(gè)用來(lái)自動(dòng)幫你釋放的池子(這特么不是廢話么)晰绎。一般情況下我們不怎么會(huì)去使用它寓落,因?yàn)樵贏ppKit和UIKit的框架中,事情基本上默認(rèn)的放在autorelease pool block中完成的荞下。這樣子當(dāng)你完成這些內(nèi)容后伶选,對(duì)應(yīng)在內(nèi)存中的數(shù)據(jù)就會(huì)自動(dòng)釋放,這樣就不需要你手動(dòng)去處理這些數(shù)據(jù)尖昏,從而保證了程序的安全性仰税。

當(dāng)然這里也提到了這是在使用AppKit和UIKit的情況下。我們?nèi)匀挥幸韵逻@幾種情況來(lái)使用autoreleasepool的情況:

  1. 編寫的是命令行程序抽诉,不基于UI框架
  2. 當(dāng)你需要寫一個(gè)循環(huán)陨簇,循環(huán)里面有很多臨時(shí)變量的時(shí)候
  3. 當(dāng)你大量使用輔助線程

總的來(lái)說(shuō)autoreleasepool是為了盡可能的減少無(wú)用變量在內(nèi)存中的占用情況。從而使得程序所需要的內(nèi)存更少掸鹅。至于autoreleasepool的釋放時(shí)間塞帐,這就要涉及到runloop,具體內(nèi)容可以參見(jiàn)sunnyxx大神的這篇文章巍沙,相信對(duì)你肯定有很大幫助葵姥。

循環(huán)引用

循環(huán)引用對(duì)于內(nèi)存來(lái)說(shuō)是一個(gè)大問(wèn)題。這個(gè)問(wèn)題我們更多的在block中可能會(huì)碰到句携,不過(guò)總結(jié)起來(lái)就是這么一句話:

A對(duì)象持有B榔幸,那么B的retain count 為1,而此時(shí)A因?yàn)楸黄渌兞砍钟邪担蠥的retain Count為1削咆,而B(niǎo)又要引用A,那么A的retain count又要加一蠢笋,這樣等到持有A的那個(gè)對(duì)象釋放A的時(shí)候拨齐,就算A的retain count減一,但還是為1昨寞,所以無(wú)法釋放瞻惋,而因?yàn)锳無(wú)法釋放,導(dǎo)致B也無(wú)法成功釋放援岩,而外部沒(méi)有持有A或B中的任意一個(gè)歼狼,這樣就導(dǎo)致了這塊內(nèi)存空間一直被持有。

圖示如下:


循環(huán)引用1

循環(huán)引用2

具體的問(wèn)題我將會(huì)在解釋block的時(shí)候具體說(shuō)明享怀,需要知道的一點(diǎn)就是羽峰,如果存在循環(huán)引用,那么就需要把循環(huán)引用中間的一條線斷掉,從而使用weak來(lái)代替梅屉,使得當(dāng)strong的一方被釋放的時(shí)候值纱,weak也能被正常釋放。

希望以上文章能夠?qū)δ阌兴鶐椭?/p>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末履植,一起剝皮案震驚了整個(gè)濱河市计雌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌玫霎,老刑警劉巖凿滤,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異庶近,居然都是意外死亡翁脆,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門鼻种,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)反番,“玉大人,你說(shuō)我怎么就攤上這事叉钥“崭祝” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵投队,是天一觀的道長(zhǎng)枫疆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)敷鸦,這世上最難降的妖魔是什么息楔? 我笑而不...
    開(kāi)封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮扒披,結(jié)果婚禮上值依,老公的妹妹穿的比我還像新娘。我一直安慰自己碟案,他們只是感情好愿险,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著价说,像睡著了一般辆亏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上熔任,一...
    開(kāi)封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天褒链,我揣著相機(jī)與錄音唁情,去河邊找鬼疑苔。 笑死,一個(gè)胖子當(dāng)著我的面吹牛甸鸟,可吹牛的內(nèi)容都是我干的惦费。 我是一名探鬼主播兵迅,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼薪贫!你這毒婦竟也來(lái)了恍箭?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瞧省,失蹤者是張志新(化名)和其女友劉穎扯夭,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鞍匾,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡交洗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了橡淑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片构拳。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖梁棠,靈堂內(nèi)的尸體忽然破棺而出置森,到底是詐尸還是另有隱情,我是刑警寧澤符糊,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布凫海,位于F島的核電站,受9級(jí)特大地震影響濒蒋,放射性物質(zhì)發(fā)生泄漏盐碱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一沪伙、第九天 我趴在偏房一處隱蔽的房頂上張望瓮顽。 院中可真熱鬧,春花似錦围橡、人聲如沸暖混。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拣播。三九已至,卻和暖如春收擦,著一層夾襖步出監(jiān)牢的瞬間贮配,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工塞赂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泪勒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像圆存,于是被迫代替她去往敵國(guó)和親叼旋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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

  • 內(nèi)存管理 簡(jiǎn)述OC中內(nèi)存管理機(jī)制沦辙。與retain配對(duì)使用的方法是dealloc還是release夫植,為什么?需要與a...
    丶逐漸閱讀 1,948評(píng)論 1 16
  • iOS內(nèi)存管理 概述 什么是內(nèi)存管理 應(yīng)用程序內(nèi)存管理是在程序運(yùn)行時(shí)分配內(nèi)存(比如創(chuàng)建一個(gè)對(duì)象,會(huì)增加內(nèi)存占用)與...
    蚊香醬閱讀 5,694評(píng)論 8 119
  • 1.1 什么是自動(dòng)引用計(jì)數(shù) 概念:在 LLVM 編譯器中設(shè)置 ARC(Automaitc Reference Co...
    __silhouette閱讀 5,082評(píng)論 1 17
  • 內(nèi)存管理是程序在運(yùn)行時(shí)分配內(nèi)存、使用內(nèi)存陌兑,并在程序完成時(shí)釋放內(nèi)存的過(guò)程阐斜。在Objective-C中,也被看作是在眾...
    蹲瓜閱讀 3,001評(píng)論 1 8
  • 概述 在iOS中開(kāi)發(fā)中诀紊,我們或多或少都聽(tīng)說(shuō)過(guò)內(nèi)存管理谒出。iOS的內(nèi)存管理一般指的是OC對(duì)象的內(nèi)存管理,因?yàn)镺C對(duì)象分...
    DamonMok閱讀 3,984評(píng)論 2 20