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内存管理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java核心技术·卷 I(原书第10版)
[美] 凯.S.霍斯特曼(Cay S. Horstmann) / 周立新 等 / 机械工业出版社 / 2016-9 / CNY 119.00
Java领域最有影响力和价值的著作之一,由拥有20多年教学与研究经验的资深Java技术专家撰写(获Jolt大奖),与《Java编程思想》齐名,10余年全球畅销不衰,广受好评。第10版根据Java SE 8全面更新,同时修正了第9版中的不足,系统全面讲解了Java语言的核 心概念、语法、重要特性和开发方法,包含大量案例,实践性强。 一直以来,《Java核心技术》都被认为是面向高级程序员的经典教......一起来看看 《Java核心技术·卷 I(原书第10版)》 这本书的介绍吧!
XML 在线格式化
在线 XML 格式化压缩工具
HEX CMYK 转换工具
HEX CMYK 互转工具