笔者开始接触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 CFTypeRef
youcreate 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 )
十“面”埋伏系列下期:多线程。
官方原文: Memory Management Policy
中方 好文: iOS内存管理策略和实践