iOS-基础

iOS-autorelease

2017-08-29  本文已影响32人  doudo

直接看第四特点内容即可。

一、实现原理

主要是通过objc_autoreleasepoolpush、objc_autoreleasepoolpop、objc_autorelease这三个函数实现的。这三个函数其实是通过AutoreleasePoolPage 的push、pop、autorelease函数来实现的。每个AutoreleasepoolPage 实例对象的大小都是 4096 个字节。

自动释放池机制就像“栈”(stack)一样。系统创建好自动释放池之后,就将其通过推入栈中;在对象上执行自动释放操作,就相当于将其放入栈顶的那个池子当中;而清空自动释放池,则相当于将其从栈中弹出。
Autoreleasepool 是一个由 AutoreleasepoolPage 双向链表的结构,其中 child 指向它的子 page,parent 指向它的父 page:

双向链表

每个线程都有个AutoreleasePool栈,

二、ARC下的使用情况

1.@autoreleasepool{}来代替“NSAutoreleasePool类对象生成、持有以及废弃”。
2.__autoreleasing修饰符来代替“调用对象的autorelease方法”。

显式的附加__autoreleasing修饰符同显式的附加__strong修饰符一样罕见。
在arc中哪些地方隐式的用到了autorelease

  1. 取得非自己生成并持有的对象。如下代码,虽然可以使用alloc/new/copy/mutableCopy以外的方法来取得对象,但该对象已被注册到autoreleasepool。
id obj = [NSMutableArray array];

包括:

+ (id)array
{
    id obj = [[NSMutableArray alloc] init];
    return obj;
}

因为该对象作为函数的返回值,编译器会自动将其注册到autoreleasepool。

  1. 在访问附有__weak修饰符的变量时,实际上必定要访问到注册到autoreleasepool的对象。
id __weak ojb1 = obj0;
NSLog(@"%@",obj1);

实际相当于:

id __weak obj1 = obj0;
id __autorelasing tmp = obj1;
NSLog(@"%@",tmp);
  1. id的指针或对象的指针在没有显式指定时会被附加上__autoreleasing修饰符。
id *obj 和NSString **obj

实际上等同于

id __autoreleasing *obj 和NSString *__autoreleasing *obj

看如下的例子,比较好理解了:

//.h
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error
//.m
NSError *error = nil;
[[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];

解释:其实它和第一种情况一样,通过alloc/new/copy/mutableCopy方法以外取得的为:非自己生成并持有的对象,(之前为返回值,现在为参数都一样),因此也会注册到autoreleasepool中。

注:下边代码会报错

NSError *error = nil;
NSError **pError = &error;

因为,赋值给对象指针时,所有权符必须一致,改为如下即可:

NSError *__strong*pError = &error;

三、AutoreleasePool的创建

1. 线程中的AutoreleasePool

2. 手动创建的场景

什么时候需要手动创建呢?

  1. 循环中创建了大量的autorelease对象,利用@autoreleasepool优化循环, 降低内存峰值。
  2. 如果你的应用程序或者线程是要长期运行的并且有可能产生大量autoreleased对象, 你应该使用autorelease pool blocks。
  3. 长期在后台中运行的任务。

四、特点

当执行push操作时,会在next的位置置为nil(哨兵对象),然后next向下移动,对象依次加入到next的位置;

AutoreleasePoolPage::Pop

参考资料:
最后的使用场景参考了iOS中autorelease的那些事儿

上一篇 下一篇

猜你喜欢

热点阅读