首先要从MRC说起,我们都知道MRC阶段,内存管理都是有程序猿手动管理的;那么就必须要说到内存管理的黄金法则:
- 自己生成的对象,自己持有(通过alloc/new/copy/mutableCopy)retain **
- 非自己生成的对象,自己也能持有(除了以alloc/new/copy/mutableCopy开头的方法)
- 不再需要持有自己持有对象时释放 release
- 无法释放非自己持有的对象
当然到了ARC时期,编译器帮我们做了这些事情,当然关于autorelease的事情也是编译帮我做的。
- autoreleasepool是什么?
自动释放池,像数据结构栈一样的结构,autorelease对象push到自动释放池,非手动创建的情况下,自动释放池会在runloop迭代结束的时候对“哨兵对象”之后的autorelease对象进行一次release操作,autorelease也会在runloop迭代结束释放。手动创建的autoreleasepool会在大括弧结束进行释放。 - 什么对象会加入到autoreleasepool?
MRC时期我们可以采用[objc autorelease], 加入到当前的自动释放池。ARC不在需要,也不允许我们如此加入,编译器会自动给我加入。那么什么对象是autorelease对象?即“黄金法则”第二条,非alloc/new/copy/mutableCopy开头的构造方法生成的对象都会先加入到autoreleasePool,比如[NSMutableArray array]、[UIImage imageNamed:@"xxx"]、[NSString stringWithFormat:@"test stringq"] - 什么情况下需要手动创建autoreleasePool
根据官方文档总共有三条情况下我们需要创建autoreleasepool。- 基于命令行的程序
- 创建辅助线程
- for 循环中创建大量的autorelease对象
- 验证一下
@implementation ViewController
__weak NSString *__weakString = nil;
__weak UIImage *__weakImage = nil;
- (void)viewDidLoad {
[super viewDidLoad];
// 1.
// NSString *string = [NSString stringWithFormat:@"haoYuhong--------计算机丝是"];
// UIImage *image = [UIImage imageNamed:@"bofang-2"];
// __weakString = string;
// __weakImage = image;
// 2.
@autoreleasepool {
UIImage *image = [UIImage imageNamed:@"bofang-2"];
NSString *string = [NSString stringWithFormat:@"haoYuhong--------计算机丝是"];
// NSString *string = [NSString stringWithFormat:@"haoYuhong"];
__weakImage = image;
__weakString = string;
}
NSLog(@"%@", __weakString);
NSLog(@"%@", __weakImage);
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"%@", __weakString);
NSLog(@"%@", __weakImage);
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(@"%@", __weakString);
NSLog(@"%@", __weakImage);
}
第一种情况下,我们会看到
2019-02-18 17:11:09.134399+0800 AutoreleasePool[25252:4061510] haoYuhong--------计算机丝是
2019-02-18 17:11:09.134563+0800 AutoreleasePool[25252:4061510] <UIImage: 0x6040000b1580>, {200, 200}
2019-02-18 17:11:09.134749+0800 AutoreleasePool[25252:4061510] haoYuhong--------计算机丝是
2019-02-18 17:11:09.134897+0800 AutoreleasePool[25252:4061510] <UIImage: 0x6040000b1580>, {200, 200}
2019-02-18 17:11:09.139543+0800 AutoreleasePool[25252:4061510] (null)
2019-02-18 17:11:09.139678+0800 AutoreleasePool[25252:4061510] (null)
第二种情况输出:
2019-02-18 17:12:24.893067+0800 AutoreleasePool[25284:4063032] (null)
2019-02-18 17:12:24.893245+0800 AutoreleasePool[25284:4063032] (null)
2019-02-18 17:12:24.893472+0800 AutoreleasePool[25284:4063032] (null)
2019-02-18 17:12:24.893592+0800 AutoreleasePool[25284:4063032] (null)
2019-02-18 17:12:24.897735+0800 AutoreleasePool[25284:4063032] (null)
2019-02-18 17:12:24.897892+0800 AutoreleasePool[25284:4063032] (null)
在没有手动添加autoreleasepool的情况下,编译自动将添加autorelease对象到主线程的自动释放池,所以对象会延迟释放。当手动添加autoreleasepool的情况下,作用域结束之后就就会释放一次,当前pool中的autorelease对象。
注意:为什么NSString对象长度我要保持在>9呢?<=9会是什么情况,这里边其中有大奥秘,点击这里看我的另一篇文章。
关于autoreleasePool的源码解析,其实千篇一律,道理都是一样的,许许多多的人都写过了,也分析了。这里我将我阅读的解析源码大神的文章附上:
网友评论