Objective-C的内存管理(2)——从MRC到ARC
栏目: Objective-C · 发布时间: 5年前
内容简介:罗里吧嗦颠三倒四,单纯的个人笔记。引用计数上一篇已经有大概讲过。在Objective-C里,每个继承自NSObject的对象都会记录自身的引用计数,一番加加减减之后,变成0就会释放掉。MRC是Mannul Reference Counting的缩写,意思也很简单,这番加加减减都靠手动管理的意思。
罗里吧嗦颠三倒四,单纯的个人笔记。
MRC
引用计数上一篇已经有大概讲过。在Objective-C里,每个继承自NSObject的对象都会记录自身的引用计数,一番加加减减之后,变成0就会释放掉。
MRC是Mannul Reference Counting的缩写,意思也很简单,这番加加减减都靠手动管理的意思。
使用时的基本原则是:管好自己。每个对象,引用别的对象时加了几次计数最终到了不用的时候就要减几次。不能多也不能少。
这样就聚焦了很多。
导致引用计数增加的操作,显式的retain不多说,剩下的就是四个关键字:alloc、new(以及new开头的方法)、copy、mutableCopy,使用这四个关键字得到的对象,就算你自己加的引用计数,回头要自己减掉。
引用计数减少的操作就是release了。
AutoRelease
AutoReleasePool是个自动释放池,加入其中的对象会延迟到Pool“结束”时释放。
在MRC中,你可以显式创建一个NSAutoReleasePool,显式地将一个对象加入进去,并显式释放AutoReleasePool:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Code benefitting from a local autorelease pool. NSObject *obj = [[[NSObject alloc] init] autorelease]; [pool release];//[pool drain];
在ARC中,需要通过特殊的语法:
@autoreleasepool { // Code benefitting from a local autorelease pool. }
默认地,每个Runloop迭代开始时会创建一个AutoReleasePool,Runloop迭代结束时释放。也就是说,当我们没有显式创建AutoReleasePool时,autorelease的对象会在Runloop迭代结束时释放。
当我们显式地创建AutoReleasePool时,其释放时机是我们决定的(显式调用release/drain或block结束)。
主动使用AutoReleasePool的目的通常是为了控制内存峰值。比如,我有一个大循环,每次循环都会创建比较大的autorelease的临时对象。如果不显式释放,这些临时对象会在整个循环结束后才一起释放,期间可能造成内存占用过高。这种情况下就可以在每次循环内声明autoreleasepool,保证临时对象不会堆积。
ARC
ARC为我们自动地做了很多,屏蔽了很多细节,理论上来说,我们只需要关注对象间的所有权关系即可。
上层机制虽然简单,涉及到的细节还是有很多的,可喜可贺的是,ARC是有 标准文档 的。简直...
ARC提供的变量修饰符有以下几个:
- __strong
- __weak
- __unsafe_unretaied
- __autoreleasing
提供的属性修饰符有:
- assign 对应的所有权类型是 __unsafe_unretained。
- copy 对应的所有权类型是 __strong。
- retain 对应的所有权类型是 __strong。
- strong 对应的所有权类型是 __strong。
- unsafe_unretained对应的所有权类型是__unsafe_unretained。
- weak 对应的所有权类型是 __weak。
(基本类型默认是assign,对象类型默认是strong)
__strong
强引用,不多说了。注意声明变量和属性时若未加说明,默认是强引用。
__weak
弱引用。当对象被释放时,weak修饰的变量会被置为nil。
仔细想想,想要实现这个特性,所有的weak变量都需要放到一个全局的map里,实现成本还是比较高的。
__unsafe_unretained
不做任何额外操作。
__autoreleasing
__autoreleasing标记的变量等价于调用autorelease方法
想到一个小问题:对于函数返回值,ARC是怎么知道要不要加引用计数呢?
看这几行代码:
- (void)testMethod { NSObject *obj = [NSObject new]; NSArray *array = [NSArray array]; // do something }
在ARC中,obj和array用完之后都会被自动释放,但是细想之下其实有不少细节。
要知道,[NSObject new]返回的对象引用计数是有+1的,而[NSArray array]并不是。
这俩玩意儿引用计数差了1,ARC是怎么知道谁要多释放一次的?
在MRC中,我们知道new出来的obj需要手动释放,而array就不需要,是通过方法的关键词进行判断。
但是方法中的关键词不应该是某种约定吗?ARC难道也会去看一个方法是否是以new开头?
看了文档之后发现...ARC还真是这么做的...
Methods in the alloc, copy, init, mutableCopy, and new families are implicitly marked __attribute__((ns_returns_retained)).
回想起来,在MRC时代,这些关键词应该是止步于约定的。而ARC或许是为了平滑过渡,把曾经的约定变成了语法规范,emmm,感觉这么搞不是很好啊。
Block内存管理
在ARC之后,内存管理的问题减少了很多,但仍然有一些遗留。其中最重要的一部分就是Block相关的内存管理。
Bridge
Core Foundation框架 (CoreFoundation.framework) 是一组 C语言 接口,它们为iOS应用程序提供基本数据管理和服务功能。
Objective-C对象和CF对象是可以直接转换的:
CFStringRef aCFString = (CFStringRef)aNSString; NSString *aNSString = (NSString *)aCFString;
然而ARC是不支持CF对象的内存管理的,这就需要我们关注谁来释放转换后的对象的问题。
在MRC中,相对来说比较简单,CFRelease和release方法是等效的,择机使用即可。
这里主要关注ARC下的情况。
根据不同需求,有3种转换方式
- __bridge (不改变对象所有权)
- __bridge_retained 或者 CFBridgingRetain() (解除 ARC 所有权)
- __bridge_transfer 或者 CFBridgingRelease() (给予 ARC 所有权)
1. __bridge
__bridge不改变对象所有权。
- OC对象转CF,仍由ARC管理,不需要显式释放
NSString *aNSString = [[NSString alloc]initWithFormat:@"test"]; CFStringRef aCFString = (__bridge CFStringRef)aNSString; // do something
- CF对象转OC,仍由CF管理,需要显式释放
CFStringRef aCFString = CFStringCreateWithCString(NULL, "test", kCFStringEncodingASCII); NSString *aNSString = (__bridge NSString *)aCFString; // do something CFRelease(aCFString);
2. __bridge_retained
所有权给CF,因此要调用CFRelease显式释放
NSString *aNSString = [[NSString alloc]initWithFormat:@"test"]; CFStringRef aCFString = (__bridge_retained CFStringRef) aNSString; // do something CFRelease(aCFString);
3. __bridge_transfer
所有权给ARC,因此无需手动管理
CFStringRef aCFString = CFStringCreateWithCString(NULL, "test", kCFStringEncodingASCII); NSString *aNSString = (__bridge_transfer NSString *)aCFString; // do something
以上所述就是小编给大家介绍的《Objective-C的内存管理(2)——从MRC到ARC》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Go 语言内存管理(二):Go 内存管理
- Objective-C的内存管理(1)——内存管理概述
- [译] 图解 Go 内存管理与内存清理
- 图解 Go 内存管理器的内存分配策略
- Go:内存管理分配
- Redis内存管理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Learning JavaScript
Shelley Powers / Oreilly & Associates Inc / 2006-10-17 / $29.99
As web browsers have become more capable and standards compliant, JavaScript has grown in prominence. JavaScript lets designers add sparkle and life to web pages, while more complex JavaScript has led......一起来看看 《Learning JavaScript》 这本书的介绍吧!