iOS - AutoreleasePool

1. 基本数据结构

objectivec 复制代码
// AutoreleasePool 的基本结构
struct AutoreleasePoolPage {
    static pthread_key_t const key = AUTORELEASE_POOL_KEY;
    magic_t const magic;
    id *next;               // 指向下一个可存放对象的地址
    pthread_t const thread; // 所属线程
    AutoreleasePoolPage * const parent;  // 双向链表结构
    AutoreleasePoolPage *child;
    uint32_t const depth;
    uint32_t hiwat;
    
    // 大小固定为 4096 字节(一个虚拟内存页的大小)
    static size_t const SIZE = PAGE_MAX_SIZE;
}

2. 存储结构

objectivec 复制代码
class AutoreleasePoolPage {
    AutoreleasePoolPage * const parent;
    AutoreleasePoolPage *child;
    
    // 存储空间
    id *begin() { return (id *) ((uint8_t *)this+sizeof(*this)); }
    id *end() { return (id *) ((uint8_t *)this+SIZE); }
}

2.2 哨兵对象

objectivec 复制代码
#define POOL_BOUNDARY nil     // 池边界标记
static inline void *push() {
    id *dest = autoreleaseFast(POOL_BOUNDARY);
    return dest;
}

3. 线程关系

3.1 TLS存储

objectivec 复制代码
// 每个线程都有自己的 AutoreleasePool 栈
static pthread_key_t key;
static void tls_dealloc(void *p) {
    if (p == (void*)EMPTY_POOL_PLACEHOLDER) return;
    AutoreleasePoolPage *page = (AutoreleasePoolPage*)p;
    page->kill();  // 清理操作
}

3.2 线程本地存储初始化

objectivec 复制代码
void tls_init() {
    _objc_pthread_key = pthread_key_create(&_objc_pthread_destroyspecific);
    AutoreleasePoolPage::key = tls_create(&_objc_autoreleasepool_deallocate);
}

4. 对象管理

4.1 添加对象

objectivec 复制代码
static inline id *autoreleaseFast(id obj) {
    AutoreleasePoolPage *page = hotPage();
    if (page && !page->full()) {
        return page->add(obj);
    } else if (page) {
        return autoreleaseFullPage(obj, page);
    } else {
        return autoreleaseNoPage(obj);
    }
}

4.2 清理对象

objectivec 复制代码
void releaseAll() {
    // 释放所有autorelease对象
    AutoreleasePoolPage *page = this;
    while (page->child) page = page->child;
    
    do {
        page->releaseUntil(page->begin());
    } while ((page = page->parent));
}

5. 生命周期管理

5.1 创建时机

objectivec 复制代码
// 1. 显式创建
@autoreleasepool {
    // 代码块
}

// 2. RunLoop 相关
void _wrapRunLoopWithAutoreleasePool(void) {
    @autoreleasepool {
        // RunLoop 逻辑
    }
}

5.2 释放时机

objectivec 复制代码
// 1. @autoreleasepool 块结束
{
    void *token = objc_autoreleasePoolPush();
    // ... 
    objc_autoreleasePoolPop(token);
}

// 2. RunLoop 迭代结束
void _runLoopIterationDidEnd() {
    objc_autoreleasePoolPop(currentPool);
}

6. 内存管理

6.1 页面管理

objectivec 复制代码
void *push() {
    id *dest;
    if (DebugPoolAllocation) {
        // ...debug code...
    }
    dest = autoreleaseFast(POOL_BOUNDARY);
    return dest;
}

static inline void pop(void *token) {
    AutoreleasePoolPage *page;
    id *stop;
    page = pageForPointer(token);
    stop = (id *)token;
    page->releaseUntil(stop);
}

6.2 溢出处理

objectivec 复制代码
static id *autoreleaseFullPage(id obj, AutoreleasePoolPage *page) {
    // 当前页满了,创建新页
    AutoreleasePoolPage *next = new AutoreleasePoolPage(page);
    page->child = next;
    return next->add(obj);
}

7. 特殊情况处理

7.1 嵌套池

objectivec 复制代码
@autoreleasepool {           // 外层池
    NSString *str1 = @"1";
    @autoreleasepool {       // 内层池
        NSString *str2 = @"2";
    }                        // str2 被释放
}                           // str1 被释放

7.2 异常处理

objectivec 复制代码
void unwinding_cleanup() {
    // 异常展开时确保 AutoreleasePool 正确清理
    AutoreleasePoolPage *page = hotPage();
    if (page) {
        pop(page->begin());
    }
}

8. 性能优化

8.1 快速路径

objectivec 复制代码
static inline id autorelease(id obj) {
    ASSERT(obj);
    id *dest __unused = autoreleaseFast(obj);
    return obj;
}

8.2 空间优化

objectivec 复制代码
// 使用一页虚拟内存(4KB)作为存储单元
#define PAGE_MAX_SIZE 4096

9. 最佳实践

9.1 手动管理

objectivec 复制代码
// 处理大量临时对象
for (int i = 0; i < largeNumber; i++) {
    @autoreleasepool {
        // 创建临时对象的代码
    }
}

9.2 子线程处理

objectivec 复制代码
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    @autoreleasepool {
        // 子线程代码
    }
});

10. 注意事项

  1. 内存峰值:
objectivec 复制代码
// 不好的做法
for (int i = 0; i < largeNumber; i++) {
    // 创建autorelease对象
}  // 在循环结束才释放

// 好的做法
for (int i = 0; i < largeNumber; i++) {
    @autoreleasepool {
        // 创建autorelease对象
    }  // 每次迭代都释放
}
  1. 线程安全:
objectivec 复制代码
// 每个线程维护自己的autoreleasepool栈
+ (void)threadEntryPoint {
    @autoreleasepool {
        // 线程代码
    }
}
  1. RunLoop关系:
objectivec 复制代码
// RunLoop每次迭代都会创建和释放autoreleasepool
void runLoopMain() {
    while (running) {
        @autoreleasepool {
            // 一次RunLoop迭代
            runLoopIteration();
        }
    }
}

这里涵盖了AutoreleasePool 的主要实现细节和使用注意事项。理解这些内容对于正确使用AutoreleasePool和优化内存管理非常重要。

总结说明:

  1. 每个AutoreleasePoolPage 存储了一个静态变量key和成员变量thread

  2. 多线程共用一个 key 用于从 TLS 中获取当前线程的的 page 实例对象

  3. 在 TLS 内部获取当前的线程,使用 key 从当前线程的一个哈希表中取出对应的 page

  4. 一个线程可能有多个 page,TLS 存储双向链表中当前线程对应的最后一个page和key之间的映射

  5. 成员变量 thread 用于判断遍历过程中的 page节点是否是当前线程的page,如果不是则跳过,向前跳一个节点(page)

相关推荐
问道飞鱼42 分钟前
【移动端知识】移动端多 WebView 互访方案:Android、iOS 与鸿蒙实现
android·ios·harmonyos·多webview互访
mascon2 小时前
U3D打包IOS的自我总结
ios
名字不要太长 像我这样就好2 小时前
【iOS】继承链
macos·ios·cocoa
karshey3 小时前
【IOS webview】IOS13不支持svelte 样式嵌套
ios
潜龙95273 小时前
第4.3节 iOS App生成追溯关系
macos·ios·cocoa
游戏开发爱好者812 小时前
iOS App 电池消耗管理与优化 提升用户体验的完整指南
android·ios·小程序·https·uni-app·iphone·webview
神策技术社区19 小时前
iOS 全埋点点击事件采集白皮书
大数据·ios·app
wuyoula20 小时前
iOS V2签名网站系统源码/IPA在线签名/全开源版本/亲测
ios
2501_9159184120 小时前
iOS 性能监控工具全解析 选择合适的调试方案提升 App 性能
android·ios·小程序·https·uni-app·iphone·webview
fishycx20 小时前
iOS 构建配置与 AdHoc 打包说明
ios