内存管理最重要的就是
谁建立谁释放的原则
,基本上能够解决咱们90%以上(笔者凭借经验猜想的数字,不要太较真)的问题,可是有时候,系统作优化,会不遵循这个原则。git
下面咱们经过一个例子来介绍:github
Mark
类@interface Mark : NSObject
+ (Mark *)newMark;
+ (Mark *)createMark;
+ (Mark *)getMark;
@end
@implementation Mark
+ (Mark *)newMark {
return [[Mark alloc] init];
}
+ (Mark *)createMark {
return [[Mark alloc] init];
}
+ (Mark *)getMark {
return [[Mark alloc] init];
}
@end
复制代码
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
Mark * mark = [Mark createMark];
Mark * mark2= [Mark getMark];
Mark * mark3= [Mark newMark];
self.mark = mark;
self.mark2 = mark2;
self.mark3 = mark3;
}
复制代码
Hopper
来查看这些代码。在
[Mark createMark]
和[Mark getMark]
的内部其实 会调用autoreleaseReturnValue
来放入到自动释放池中。[Mark newMark]
会自动返回,给持有的人swift
void * +[Mark newMark](void * self, void * _cmd) {
rax = [Mark alloc];
rax = [rax init];
return rax;
}
void * +[Mark createMark](void * self, void * _cmd) {
rax = [[Mark alloc] init];
rax = [rax autorelease];
return rax;
}
void * +[Mark getMark](void * self, void * _cmd) {
rax = [[Mark alloc] init];
rax = [rax autorelease];
return rax;
}
复制代码
在控制器中,咱们能够知道bash
对于
[[Mark createMark] retain]
和[[Mark getMark] retain]
其实伪代码有些错误
,咱们经过查看汇编代码能够知道会有个imp___stubs__objc_retainAutoreleasedReturnValue
,其实就是把autoRelease
和retain
合并起来,这样就不用再注入到自动释放池中
.数据结构
void -[AutoReleaseVC viewDidLoad](void * self, void * _cmd) {
rax = var_20;
[[rax super] viewDidLoad];
var_28 = [[Mark createMark] retain];
var_30 = [[Mark getMark] retain];
var_38 = [Mark newMark];
[self setMark:var_28];
[self setMark2:var_30];
[self setMark3:var_38];
objc_storeStrong(var_38, 0x0);
objc_storeStrong(var_30, 0x0);
objc_storeStrong(var_28, 0x0);
return;
}
复制代码
首先咱们要搞清两个概念,一个是
autoreleasepool
,另一个是AutoreleasePoolPage
,带着这两个问题,咱们看下面例子。iphone
-rewrite-objc
查看cpp代码- (void)testAutoPool {
@autoreleasepool {
NSObject * obj = [[NSObject alloc] init];
NSLog(@"obj = %@",obj);
}
}
复制代码
经过命令 xcrun -sdk iphoneos clang -rewrite-objc -F Foundation -arch arm64 Auto.m
, 咱们看看 @autoreleasepool
究竟是什么东西?优化
static void _I_AutoModel_testAutoPool(AutoModel * self, SEL _cmd) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
NSObject * obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_zx_py2__3n12pd_dj7nkk36jzqm0000gn_T_AutoModel_b08238_mi_0,obj);
}
}
struct __AtAutoreleasePool {
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};
复制代码
再经过Hopper
咱们能够更加清楚看到ui
void -[AutoModel testAutoPool](void * self, void * _cmd) {
var_28 = objc_autoreleasePoolPush();
var_18 = [[NSObject alloc] init];
NSLog(@"obj = %@", var_18);
objc_storeStrong(var_18, 0x0);
objc_autoreleasePoolPop(var_28);
return;
}
复制代码
其实
@autoreleasepool{}
内部就是 经过var_28 = objc_autoreleasePoolPush()
和objc_autoreleasePoolPop(var_28);
来做用的spa
经过查找源码objc4-723
中的NSObject.mm
,咱们能够查看到 AutoreleasePoolPage
,而后咱们查看一下它的数据结构和一些方法线程
class AutoreleasePoolPage {
magic_t const magic;
id *next;
// 说明 一个 autoreleasePool 对应一个线程
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
};
void *objc_autoreleasePoolPush(void) {
return AutoreleasePoolPage::push();
}
void objc_autoreleasePoolPop(void *ctxt) {
AutoreleasePoolPage::pop(ctxt);
}
复制代码
咱们应该很清楚的知道,AutoreleasePoolPage 是一个 双向链表,为何要设置多张Page,其实系统仍是为了节省空间,相似咱们的内存分页的思想。
经过
autpreleasePoolPush
设置哨兵nil
也就是begain
, 里面有个next
指针指定了下个obj的位置,也就是end
。那么在调用autoreleasePoolPop
的时候其实就是释放end - begain
的空间,同时 给这里的每一个对象都发送一个release
方法。
桥接主要设计到下面几个方法,其实CFBridgingRetain
内部是调用 __bridge_retained
的; CFBridgingRelease
内部也是调用 __bridge_transfer
;
__bridge
: 不会改变原来的ownership
;p = (__bridge_retained void *)obj
和 p = (void *) CFBridgingRetain(obj)
: 把OC里面的ARCownership
全部权,给CF类型的对象
;(id)CFBridgingRelease(p)
和 (__bridge_transfer id)p
: 把CF的ownership
全部权,交给 OC对象
;CF对象 = (__bridge void *)OC对象
经过
__bridge
把OC 转换成CF
- (void)brigeTest1 {
void * p = 0;
{
id obj = [NSObject new];
p = (__bridge void *)obj;
}
// 直接崩溃,由于p 不持有 obj 对象, 当 {} 结束的时候,obj被释放了, 因此致使崩溃
NSLog(@" p = %@",p);
}
复制代码
CF对象 = (__bridge_retained void *)OC对象
或者 CF对象 = (void *) CFBridgingRetain(OC对象)
- (void)brigeTest2 {
void * p = 0;
{
id obj = [NSObject new];
p = (__bridge_retained void *)obj;
}
NSLog(@" p = %@",p);
CFBridgingRelease(p);
}
- (void)brigeTest3 {
void * p = 0;
{
id obj = [NSObject new];
p = (void *) CFBridgingRetain(obj);
}
// 直接崩溃,由于p 不持有 obj 对象, 当 {} 结束的时候,obj被释放了, 因此致使崩溃
NSLog(@" p = %@",p);
CFBridgingRelease(p);
}
复制代码
id o = (__bridge id)p
- (void)test {
// 生成 CF p
void * p = 0;
id obj = [NSObject new];
p = (void *) CFBridgingRetain(obj);
// OC 对象
// 无论理p的内存
//Use __bridge to convert directly (no change in ownership)
//使用 __bridge 不会改变 p的全部权
id o = (__bridge id)p;
}
复制代码
id o1 = (id)CFBridgingRelease(p)
和 id o2 = (__bridge_transfer id)p
- (void)test {
// 生成 CF p
void * p = 0;
id obj = [NSObject new];
p = (void *) CFBridgingRetain(obj);
// OC 对象
//Use CFBridgingRelease call to transfer ownership of a +1 'void *' into ARC
// 把p的全部权转移给 oc对象持有
id o1 = (id)CFBridgingRelease(p);
// 和 CFBridgingRelease 等价
id o2 = (__bridge_transfer id)p;
}
复制代码
参考