iOS內存管理機制的原理是引用計數,引用計數簡單來講就是統計一塊內存的全部權,當這塊內存被建立出來的時候,它的引用計數從0增長到1,表示有一個對象或指針持有這塊內存,擁有這塊內存的全部權,若是這時候有另一個對象或指針指向這塊內存,那麼爲了表示這個後來的對象或指針對這塊內存的全部權,引用計數加1變爲2,以後如有一個對象或指針再也不指向這塊內存時,引用計數減1,表示這個對象或指針再也不擁有這塊內存的全部權,當一塊內存的引用計數變爲0,表示沒有任何對象或指針持有這塊內存,系統便會馬上釋放掉這塊內存。數組
其中在開發時引用計數又分爲ARC(自動內存管理)和MRC(手動內存管理)。ARC的本質其實就是MRC,只不過是系統幫助開發者管理已建立的對象或內存空間,自動在系統認爲合適的時間和地點釋放掉已經失去做用的內存空間,原理是同樣的。雖然ARC操做起來很方便,不但減小了代碼量,並且下降了內存出錯的機率,但由於ARC不必定會及時釋放,因此程序有時候可能會佔用內存較大。而MRC若作得好,經過手動管理,及時釋放掉不須要的內存空間,即可保證程序長時間運行在良好狀態上。spa
在MRC中會引發引用計數變化的關鍵字有:alloc,retain,copy,release,autorelease。(strong關鍵字只用於ARC,做用等同於retain)指針
alloc:當一個類的對象建立,須要開闢內存空間的時候,會使用alloc,alloc是一個類方法,只能用類調用,它的做用是開闢一塊新的內存空間,並使這塊內存的引用計數從0增長到1,注意,是新的內存空間,每次用類alloc出來的都是一塊新的內存空間,與上一次alloc出來的內存空間沒有必然聯繫,並且上一次alloc出來的內存空間仍然存在,不會被釋放。對象
retain:retain是一個實例方法,只能由對象調用,它的做用是使這個對象的內存空間的引用計數加1,並不會新開闢一塊內存空間,一般於賦值是調用,如:內存
對象2=[對象1 retain];表示對象2一樣擁有這塊內存的全部權。若只是簡單地賦值,如:對象2=對象1;那麼當對象1的內存空間被釋放的時候,對象2便會成爲野指針,再對對象2進行操做便會形成內存錯誤。開發
copy:copy一樣是一個實例方法,只能由對象調用,返回一個新的對象,它的做用是複製一個對象到一塊新的內存空間上,舊內存空間的引用計數不會變化,新的內存空間的引用計數從0增長到1,也就是說,雖然內容同樣,但實質上是兩塊內存,至關於克隆,一個變成兩個。其中copy又分爲淺拷貝、深拷貝和真正的深拷貝,淺拷貝只是拷貝地址與retain等同;深拷貝是拷貝內容,會新開闢新內存,與retain不同;真正的深拷貝是對於容器類來講的,如數組類、字典類和集合類(包括可變和不可變),假設有一個數組類對象,普通的深拷貝會開闢一塊新內存存放這個對象,但這個數組對象裏面的各個元素的地址卻沒有改變也就是說數組元素只是進行了retain或者淺拷貝而已,並無建立新的內存空間,而真正的深拷貝,不但數組對象自己進行了深拷貝,連數組元素都進行了深拷貝,即爲各個數組元素開闢了新的內存空間。it
release:release是一個實例方法,一樣只能由對象調用,它的做用是使對象的內存空間的引用計數減1,若引用計數變爲0則系統會馬上釋放掉這塊內存。若是引用計數爲0的基礎上再調用release,便會形成過分釋放,使內存崩潰;內存管理
autorelease:autorelease是一個實例方法,一樣只能由對象調用,它的做用於release相似,但不是馬上減1,至關於一個延遲的release,一般用於方法返回值的釋放,如便利構造器。autorelease會在程序走出自動釋放池時執行,一般系統會自動生成自動釋放池(即便是MRC下),也能夠本身設定自動釋放池,如:io
@autoreleasepool{容器
obj= [[NSObject alloc]init];
[obj autorelease];
}
當程序走出「}」時obj的引用計數就會減1.
除了以上所述的關鍵字,還有一些方法會引發引用計數的變化,如UI中父視圖添加、移除子視圖,導航控制器或視圖控制器推出新的視圖控制器以及返回,容器類(數組、字典和集合)添加和移除元素。
當子視圖添加到父視圖上時,子視圖的引用計數加1,移除時引用計數減1,若父視圖引用計數變爲0內存被釋放,其全部的子視圖都會被release一次,即引用計數減1,原則上只有這三種狀況子視圖的引用計數會發生變化,其餘如父視圖引用計數的加減都不會影響到子視圖。
容器類的狀況與視圖相似,添加元素,該元素引用計數加1,移除元素,該元素引用計數減1,容器引用計數變爲0所佔用內存被釋放,容器全部元素release,引用計數減1,其餘狀況下容器自己的引用計數變化不會影響到容器內元素的引用計數變化。
導航控制器或視圖控制器推出新的視圖控制器會使被推出的視圖控制器的引用計數加1,該視圖控制器返回的時候引用計數減1,具體方法以下:
導航控制器推出視圖控制器調用方法:- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
返回時一樣用導航控制器調用方法:- (UIViewController *)popViewControllerAnimated:(BOOL)animated;
視圖控制器推出視圖控制器調用方法:- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion
返回時被推出的視圖控制器調用方法:- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion
應注意:當一個對象的引用計數變爲0佔用內存被釋放時,會調用- (void)dealloc方法,因此若是在MRC下自定義類,必須在該方法裏將該類中屬性關鍵字設置爲retain或copy的屬性release一次,以避免形成內存泄露,重寫方法不要忘記在第一行添加[super dealloc];。