autorelease = 延遲調用release。對象被加入當前AutoreleasePool,Pooldrain時統一release。
__weak NSString *weakStr = nil;
- (void)viewDidLoad {
[super viewDidLoad];
// 场景1:無手動pool
NSString *str = [NSString stringWithFormat:@"leichunfeng"];
weakStr = str;
NSLog(@"%@", weakStr); // 有值
// 场景2:手動@autoreleasepool {}
// @autoreleasepool {
// NSString *str = [NSString stringWithFormat:@"leichunfeng"];
// weakStr = str;
// }
// NSLog(@"%@", weakStr); // nil,pool結束已釋放
// 场景3:變量在pool外,對象在pool內
// NSString *str = nil;
// @autoreleasepool { str = [NSString stringWithFormat:@"leichunfeng"]; weakStr = str; }
// NSLog(@"%@", weakStr); // 有值(str強引用持有)
// viewDidLoad返回後str釋放 → weakStr變nil
}
Console輸出對比:
| 場景 | viewDidLoad | viewWillAppear | viewDidAppear |
|---|---|---|---|
| 1. 無手動pool | 有值 | 有值 | nil |
| 2. 手動pool內 | nil | nil | nil |
| 3. 變量外對象內 | 有值 | nil | nil |
Runtime源碼(objc4-646)揭示:
POOL_SENTINEL(哨兵,標記pool邊界)AutoreleasePoolPage節點(每頁4KB)hotPage(最新分配頁)struct AutoreleasePoolPage {
uint32_t magic; // 魔數校驗
id *next; // 下一個可用槽位
pthread_t thread; // 所屬線程
AutoreleasePoolPage *parent; // 父頁
AutoreleasePoolPage *child; // 子頁
uint32_t depth; // 深度
uint32_t hiwat; // 高水位線
};
void *objc_autoreleasePoolPush() {
return AutoreleasePoolPage::push(); // 插入POOL_SENTINEL,返回其地址(token)
}
- (id)autorelease { return [self autorelease]; }
// 最终调用
id AutoreleasePoolPage::autorelease(id obj) {
id *dest = autoreleaseFast(obj); // 同push邏輯插入對象指針
return obj;
}
void objc_autoreleasePoolPop(void *token) {
AutoreleasePoolPage::pop(token); // 從token位置向後,所有對象release,直到哨兵
}
token之後所有對象next指針回退到token位置// Objective-C
@autoreleasepool { ... }
// Clang重寫為C++
struct __AtAutoreleasePool {
void *token;
__AtAutoreleasePool() { token = objc_autoreleasePoolPush(); }
~__AtAutoreleasePool() { objc_autoreleasePoolPop(token); }
};
{ __AtAutoreleasePool pool; ... } // RAII模式:構造push,析構pop
push,結束時popNSThread入口函數添加pool)// 設置觀察點監控weak變量變化 (lldb) watchpoint set v weakStr // 運行至釋放點,堆棧顯示 -[NSAutoreleasePool release] → AutoreleasePoolPage::pop