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)

相关推荐
openinstall全渠道统计16 小时前
免填邀请码工具:赋能六大核心场景,重构App增长新模型
android·ios·harmonyos
早起的年轻人21 小时前
Flutter CupertinoNavigationBar iOS 风格导航栏的组件
flutter·ios
貂蝉空大1 天前
uni-app开发安卓和ios app 真机调试
android·ios·uni-app
胖虎11 天前
iOS 中的圆角与平滑圆角:从新特性到老项目适配
ios·圆角·平滑圆角·cornercurve
志飞1 天前
ios UICollectionView使用自定义UICollectionViewCell
ios·collectionview·自定义cell
Neo Evolution1 天前
Flutter与移动开发的未来:谷歌的技术愿景与实现路径
android·人工智能·学习·ios·前端框架·webview·着色器
没头脑的ht2 天前
ios App的启动过程和启动优化
ios
敲代码的鱼哇2 天前
设备唯一ID获取,支持安卓/iOS/鸿蒙Next(uni-device-id)UTS插件
android·ios·uniapp·harmonyos
江上清风山间明月2 天前
Flutter最简单的路由管理方式Navigator
android·flutter·ios·路由·页面管理·navigator
fangcaojushi2 天前
解决videojs在ios端视频无法播放的问题
ios·音视频