軟件運(yùn)行時(shí)會(huì)分配和使用設(shè)備的內(nèi)存資源,因此,在軟件開(kāi)發(fā)的過(guò)程中,需要進(jìn)行內(nèi)存管理,以保證高效、快速的分配內(nèi)存,并且在適當(dāng)?shù)臅r(shí)候釋放和回收內(nèi)存資源。
一、Objective-C內(nèi)存管理的對(duì)象
IOS開(kāi)發(fā)中,內(nèi)存中的對(duì)象主要有兩類(lèi),一類(lèi)是值類(lèi)型,比如int、float、struct等基本數(shù)據(jù)類(lèi)型,另一類(lèi)是引用類(lèi)型,也就是繼承自NSObject類(lèi)的所有的OC對(duì)象。前一種值類(lèi)型不需要我們管理,后一種引用類(lèi)型是需要我們管理內(nèi)存的,一旦管理不好,就會(huì)產(chǎn)生非常糟糕的后果。
為什么值類(lèi)型不需要管理,而引用類(lèi)型需要管理呢?那是因?yàn)樗麄兎峙鋬?nèi)存方式不一樣。
值類(lèi)型會(huì)被放入棧中,他們依次緊密排列,在內(nèi)存中占有一塊連續(xù)的內(nèi)存空間,遵循先進(jìn)后出的原則。引用類(lèi)型會(huì)被放到堆中,當(dāng)給對(duì)象分配內(nèi)存空間時(shí),會(huì)隨機(jī)的從內(nèi)存當(dāng)中開(kāi)辟空間,對(duì)象與對(duì)象之間可能會(huì)留有不確定大小的空白空間,因此會(huì)產(chǎn)生很多內(nèi)存碎片,需要我們管理。
棧內(nèi)存與堆內(nèi)存從性能上比較,棧內(nèi)存要優(yōu)于堆內(nèi)存,這是因?yàn)闂W裱冗M(jìn)后出的原則,因此當(dāng)數(shù)據(jù)量過(guò)大時(shí),存入棧會(huì)明顯的降低性能。因此,我們會(huì)把大量的數(shù)據(jù)存入堆中,然后棧中存放堆的地址,當(dāng)需要調(diào)用數(shù)據(jù)時(shí),就可以快速的通過(guò)棧內(nèi)的地址找到堆中的數(shù)據(jù)。
值類(lèi)型和引用類(lèi)型之間是可以相互轉(zhuǎn)化的,把值類(lèi)型轉(zhuǎn)化為引用類(lèi)型的過(guò)程叫做裝箱,比如把int包裝為NSNumber,這個(gè)過(guò)程會(huì)增加程序的運(yùn)行時(shí)間,降低性能。而把引用類(lèi)型轉(zhuǎn)為值類(lèi)型的過(guò)程叫做拆箱,比如把NSNumer轉(zhuǎn)為float,在拆箱的過(guò)程中,我們一定要注意數(shù)據(jù)原有的類(lèi)型,如果類(lèi)型錯(cuò)誤,可能導(dǎo)致拆箱失敗,因此會(huì)存在安全性的問(wèn)題。手動(dòng)的拆箱和裝箱,都會(huì)增加程序的運(yùn)行時(shí)間,降低代碼可讀性,影響性能。
在IOS開(kāi)發(fā)過(guò)程中,棧內(nèi)存中的值類(lèi)型系統(tǒng)會(huì)自動(dòng)管理,堆內(nèi)存中的引用類(lèi)型是需要我們管理的。每個(gè)OC對(duì)象內(nèi)部都專(zhuān)門(mén)有四個(gè)字節(jié)來(lái)存儲(chǔ)引用計(jì)數(shù)器,它是一個(gè)整數(shù),表示對(duì)象被引用的次數(shù),通過(guò)它可以判斷對(duì)象是否被回收,如果引用計(jì)數(shù)為0,對(duì)象回收,不為0不回收。當(dāng)對(duì)象執(zhí)行alloc、new或者retain時(shí),引用計(jì)數(shù)加1,release時(shí),引用計(jì)數(shù)減1。
二、Objective-C管理內(nèi)存的方式
Objective-c中提供了兩種內(nèi)存管理機(jī)制MRC(Mannul Reference Counting)和ARC(Automatic Reference Counting),分別提供對(duì)內(nèi)存的手動(dòng)和自動(dòng)管理,來(lái)滿(mǎn)足不同的需求。MRC與ARC區(qū)別如下圖所示。

IOS 內(nèi)存管理
1.MRC(人工引用計(jì)數(shù)),手動(dòng)管理內(nèi)存。
MRC模式下,所有的對(duì)象都需要手動(dòng)的添加retain、release代碼來(lái)管理內(nèi)存。使用MRC,需要遵守誰(shuí)創(chuàng)建,誰(shuí)回收的原則。也就是誰(shuí)alloc,誰(shuí)release;誰(shuí)retain,誰(shuí)release。
當(dāng)引用計(jì)數(shù)為0的時(shí)候,必須回收,引用計(jì)數(shù)不為0,不能回收,如果引用計(jì)數(shù)為0,但是沒(méi)有回收,會(huì)造成內(nèi)存泄露。如果引用計(jì)數(shù)為0,繼續(xù)釋放,會(huì)造成野指針。為了避免出現(xiàn)野指針,我們?cè)卺尫诺臅r(shí)候,會(huì)先讓指針=nil。
2.ARC(自動(dòng)引用計(jì)數(shù)),自動(dòng)管理內(nèi)存。
ARC是IOS5推出的新功能,通過(guò)ARC,可以自動(dòng)的管理內(nèi)存。在ARC模式下,只要沒(méi)有強(qiáng)指針(強(qiáng)引用)指向?qū)ο?,?duì)象就會(huì)被釋放。在ARC模式下,不允許使用retain、release、retainCount等方法。并且,如果使用dealloc方法時(shí),不允許調(diào)用[super dealloc]方法。
ARC模式下的property變量修飾詞為strong、weak,相當(dāng)于MRC模式下的retain、assign。strong :代替retain,缺省關(guān)鍵詞,代表強(qiáng)引用。weak:代替assign,聲明了一個(gè)可以自動(dòng)設(shè)置nil的弱引用,但是比assign多一個(gè)功能,指針指向的地址被釋放之后,指針本身也會(huì)自動(dòng)被釋放。
三、與內(nèi)存有關(guān)的修飾符
strong :強(qiáng)引用,ARC中使用,與MRC中retain類(lèi)似,使用之后,計(jì)數(shù)器+1。
weak :弱引用 ,ARC中使用,如果只想的對(duì)象被釋放了,其指向nil,可以有效的避免野指針,其引用計(jì)數(shù)為1。
readwrite : 可讀可寫(xiě)特性,需要生成getter方法和setter方法時(shí)使用。
readonly : 只讀特性,只會(huì)生成getter方法 不會(huì)生成setter方法,不希望屬性在類(lèi)外改變。
assign :賦值特性,不涉及引用計(jì)數(shù),弱引用,setter方法將傳入?yún)?shù)賦值給實(shí)例變量,僅設(shè)置變量時(shí)使用。
retain :表示持有特性,setter方法將傳入?yún)?shù)先保留,再賦值,傳入?yún)?shù)的retaincount會(huì)+1。
copy :表示拷貝特性,setter方法將傳入對(duì)象復(fù)制一份,需要完全一份新的變量時(shí)。
nonatomic :非原子操作,不加同步,多線程訪問(wèn)可提高性能,但是線程不安全的。決定編譯器生成的setter getter是否是原子操作。
atomic :原子操作,同步的,表示多線程安全,與nonatomic相反。
四、MRC與ARC混編
MRC與ARC理論上是不能兼容的,也就是你如果創(chuàng)建的項(xiàng)目是ARC模式的,在你的代碼中是不能使用release,否則會(huì)出現(xiàn)內(nèi)存問(wèn)題?,F(xiàn)在大部分程序都會(huì)選擇ARC的方式,但是很多第三方的框架是MRC模式,如果想把這些第三方的文件加到自己項(xiàng)目中,需要進(jìn)行標(biāo)識(shí),否則編譯的時(shí)候會(huì)出現(xiàn)錯(cuò)誤。
在ARC的項(xiàng)目中,對(duì)MRC的文件可以添加編譯選項(xiàng)-fno-objc-arc的標(biāo)識(shí);在MRC的項(xiàng)目中,對(duì)ARC的文件可以添加編譯選項(xiàng) -fobjc-arc的標(biāo)識(shí)。 步驟如下圖所示。

IOS 內(nèi)存管理
把MRC文件轉(zhuǎn)為ARC,實(shí)際上是去掉文件中的retain、release,因此也通過(guò)下圖中方式完成。

原文出處:http://www.itdecent.cn/p/66b5d43b6ac4