關於autoreleasepool記憶體管理

weixin_34232744發表於2019-02-18

首先要從MRC說起,我們都知道MRC階段,記憶體管理都是有程式猿手動管理的;那麼就必須要說到記憶體管理的黃金法則:

  1. 自己生成的物件,自己持有(通過alloc/new/copy/mutableCopy)retain **
  2. 非自己生成的物件,自己也能持有(除了以alloc/new/copy/mutableCopy開頭的方法)
  3. 不再需要持有自己持有物件時釋放 release
  4. 無法釋放非自己持有的物件
    當然到了ARC時期,編譯器幫我們做了這些事情,當然關於autorelease的事情也是編譯幫我做的。
  1. autoreleasepool是什麼?
    自動釋放池,像資料結構棧一樣的結構,autorelease物件push到自動釋放池,非手動建立的情況下,自動釋放池會在runloop迭代結束的時候對“哨兵物件”之後的autorelease物件進行一次release操作,autorelease也會在runloop迭代結束釋放。手動建立的autoreleasepool會在大括弧結束進行釋放。
  2. 什麼物件會加入到autoreleasepool?
    MRC時期我們可以採用[objc autorelease], 加入到當前的自動釋放池。ARC不在需要,也不允許我們如此加入,編譯器會自動給我加入。那麼什麼物件是autorelease物件?即“黃金法則”第二條,非alloc/new/copy/mutableCopy開頭的構造方法生成的物件都會先加入到autoreleasePool,比如[NSMutableArray array]、[UIImage imageNamed:@"xxx"]、[NSString stringWithFormat:@"test stringq"]
  3. 什麼情況下需要手動建立autoreleasePool
    根據官方文件總共有三條情況下我們需要建立autoreleasepool。
    • 基於命令列的程式
    • 建立輔助執行緒
    • for 迴圈中建立大量的autorelease物件
  4. 驗證一下
@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的原始碼解析,其實千篇一律,道理都是一樣的,許許多多的人都寫過了,也分析了。這裡我將我閱讀的解析原始碼大神的文章附上:

黑幕背後的Autorelease
https://www.jianshu.com/p/66282c943c04

相關文章