筆者開始接觸iOS也有一段時間了,從最初只會寫NSLog的菜鳥到能使用基本控件布局完成簡單的頁面布局,再到了解核心動畫的寫法,每一步都很倍感欣慰,途中遇到各種各樣的問題,各種莫名其妙的“崩潰”,慶幸的是我不曾沮喪,相反面對bug面對崩潰我卻很積極,原因是在尋找bug和問題出處的時候我異常專注,我似乎可以感受到那種腦電流flow在我的大腦中,雖有時也難免會有百思不得其解的尴尬和窮途末路的絕望,但每逢柳暗花明又一村的迎來解決的方法時,便覺得一切都值了,滿滿的都是笑容。
臨近出師翻看了很多關於面試相關的題目,一方面檢測自己這段時間到底學會了那些東西,另一方面也重新梳理下知識網絡查缺補漏。一千個人眼中就有一千個哈姆雷特,對於一個知識點除了蘋果官方文檔作為范本為各開發者所敬仰,作為更多開發者的我們相比都會有自己的看法,或成熟或幼稚,可總歸是有才好。博文內容在其他博主部落格或許可以找到相關或者相似,但筆者認為一個好的iOS開發者應有自己的見解,同時書寫博客也是對於自己漫漫學習歷程的記錄和沉澱。
廢話到此為止,進入今天的正題:內存管理機制ARC和MRC.
-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
iAronTalk Blog opens.
Even if the present, the match does not stop changes the page.
-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Part 1:面試問題集(積累-ing)
=-=-01.ARC下,不顯式指定任何屬性關鍵字時,默認的關鍵字都有哪些?
Answer:atomic,readwrite,strong(對象),assgin(基本數據類型)。
=-=-02.objc中,ARC/MRC分別都是如何進行內存管理的?
Answer:參考下文。
Part 2:知識點小節
程序運行過程中系統會創建大量的對象,跟大多數的高級語言一樣,在ObjC中對象存儲在堆中,系統並不會自動釋放堆中的內存,需要注意的時基本類型是由系統自己管理的,放在棧上。如果一個對象創建並使用後沒有得到及時釋放那麼就會占用大量內存,內存的積累使得系統卡慢,嚴重程序會直接崩潰掉。其他高級語言如C#、Java都是通過垃圾回收來(GC)解決這個問題的,但在OjbC中並沒有類似的垃圾回收機制,因此蘋果想出了采用引用計數這個概念來對內存中的對象進行管理,在SDK4.0之前使用的是MRC,即手動內存管理,在4.0之後蘋果引入了ARC(自動內存管理),大大的節省了開發人員的時間,以往勞神費力的手動內存管理時代漸漸遠去,但在遇到底層Core Foundation對象就需要自己手工管理引用計數了。
關於內存管理:“程序運行時,開辟的內存空間。使用它,釋放它”的過程,寫的好的程序盡可能少使用內存。在Objective-C中,內存管理被看做是:“在很多數據、代碼下,分配受限內存資源所有權方法”。當你依據這個指南完成你的程序時,你將獲得“通過 顯式管理對象的命周期,不使用的時候釋放他們,來管理程序內存”的知識。
縱觀整個iOS開發中的內存管理,深層次上是對內存中對象的合理保留和釋放,但是淺層次上無疑是引用計數世界。我們不曾直接的對內存進行任何操作,而一切的操作都是起於引用計數,止於引用計數。無論ARC和MRC,都是對引用計數的不同操作而已。
=-=-Section A:Objective-c語言中的MRC(MannulReference Counting)
**01.在MRC的內存管理模式下,與對變量的管理相關的方法有:retain,release和autorelease。retain和release方法操作的是引用記數,當引用記數為零時,便自動釋放內存。並且可以用NSAutoreleasePool對象,對加入自動釋放池(autorelease調用)的變量進行管理,當drain時回收內存。
(1)retain,該方法的作用是將內存數據的所有權附給另一指針變量,引用數加1,即retainCount+= 1;
(2)release,該方法是釋放指針變量對內存數據的所有權,引用數減1,即retainCount-= 1;
(3)autorelease,該方法是將該對象內存的管理放到autoreleasepool中。
示例代碼:
//假設Person為預定義的類
Person* person = [[Person alloc] init];
[person retain];//此時引用記數+1,現為2
[person release];//person釋放對內存數據的所有權 引用記數-1,現為0;
[person run];//出現野指針,此時內存已釋放。
**02.//autoreleasepool 的使用 在MRC管理模式下,最新方法是@autoreleasepool
@autoreleasepool {
Person* person = [[Person alloc] init];
[person autorelease];//由autoreleasepool來管理其內存的釋放
}
**03.標識符@property (nonatomic/atomic,retain/assign/copy, readonly/readwrite) Number* num;
1)nonatomic/atomic,表示該屬性是否是對多線程安全的,是不是使用線程鎖,默認為atomic,
2)retain/assign/copy,是有關對該屬性的內存管理的,
l assign"is the default. In the setter that is created by @synthesize, the value willsimply be assigned to the attribute, don’t operate the retain count. Myunderstanding is that "assign" should be used for non-pointer attributes.
l "retain"is needed when the attribute is a pointer to an object. The setter generated by@synthesize will retain (aka add a retain count) the object. You will need torelease the object when you are finished with it.
l "copy"is needed when the object is mutable. Use this if you need the value of theobject as it is at this moment, and you don't want that value to reflect anychanges made by other owners of the object. You will need to release the objectwhen you are finished with it because you are retaining the copy.
(3)readwrite /readonly -"readwrite" is the default. When you @synthesize, both a getter and asetter will be created for you. If you use "readonly", no setter willbe created. Use it for a value you don't want to ever change after the instantiationof the object.
=-=-Section B:Objective-c語言中的ARC(AutomaticReference Counting)
**01.在ARC中與內存管理有關的標識符,可以分為變量標識符和屬性標識符,對於變量默認為__strong,而對於屬性默認為unsafe_unretained。也存在 autoreleasepool。
對於變量的標識符有:
1) __strong,is the default. An object remains “alive” as long as there is a strong pointerto it.
2) __weak,specifies a reference that does not keep the referenced object alive. A weakreference is set to nil when there are no strong references to the object.
3)__unsafe_unretained,specifies a reference that does not keep the referenced object alive and is notset to nil when there are no strong references to the object. If the object itreferences is deallocated, the pointer is left dangling.
4)__autoreleasing,is used to denote arguments that are passed by reference (id *) and areautoreleased on return,managedby Autoreleasepool.
**02.對於變量標識符的用法:
__strong Person* person = [[Person alloc]init];
在ARC內存管理模式下,其屬性的標識符存在以下幾種:
**03.@property (nonatomic/atomic, assign/retain/strong/weak/unsafe_unretained/copy,readonly/readwrite) Number* num;//默認為 unsafe_unretained
其中assign/retain/copy與MRC下property的標識符意義相同,strong類似與retain,assign類似於unsafe_unretained,strong/weak/unsafe_unretained與ARC下變量標識符意義相同,只是一個用於屬性的標識,一個用於變量的標識(帶兩個下劃短線__)。所列出的其他的標識符與MRC下意義相同。
(1)對於assign,你可以對標量類型(如int)使用這個屬性。你可以想象一個float,它不是一個對象,所以它不能retain、copy。
(2)對於copy,指定應該使用對象的副本(深度復制),前一個值發送一條release消息。基本上像retain,但是沒有增加引用計數,是分配一塊新的內存來放置它。
特別適用於NSString,如果你不想改變現有的,就用這個,因為NSMutableString,也是NSString。
**04.對於Core Foundation與objective-cObject進行交換時,需要用到的ARC管理機制有:
1) (__bridge_transfer<NSType>) op oralternatively CFBridgingRelease(op) isused to consume a retain-count of a CFTypeRef whiletransferring it over to ARC. This could also be represented by id someObj =(__bridge <NSType>) op; CFRelease(op);
2) (__bridge_retained<CFType>) op oralternatively CFBridgingRetain(op) isused to hand an NSObject overto CF-land while giving it a +1 retain count. You should handle a CFTypeRefyoucreate this way the same as you would handle a result of CFStringCreateCopy().This could also be represented by CFRetain((__bridge CFType)op); CFTypeRef someTypeRef =(__bridge CFType)op;
3) __bridge justcasts between pointer-land and Objective-C object-land. If you have noinclination to use the conversions above, use this one.
=-=-Section C:Objectiv使用分析工具來調試內存問題
在編譯時候找出代碼的問題。使用Xcode內嵌的Clang Static Analyzer 。
如果內存管理的問題仍然發生,還有其他的工具和技術,你可以用它來識別和診斷問題。
1.多數工具和技術都在TN2239中有描述,iOS Debugging Magic 特別是NSZombie來幫助找到過度釋放對象。
2.使用Instruments來追蹤引用計數事件並找到內存洩露。( 參考 Collecting Data on Your App)