当前位置: 首页 > news >正文

iOS - AutoreleasePool

1. 基本数据结构

// 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. 存储结构

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 哨兵对象

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

3. 线程关系

3.1 TLS存储

// 每个线程都有自己的 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 线程本地存储初始化

void tls_init() {_objc_pthread_key = pthread_key_create(&_objc_pthread_destroyspecific);AutoreleasePoolPage::key = tls_create(&_objc_autoreleasepool_deallocate);
}

4. 对象管理

4.1 添加对象

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 清理对象

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

5. 生命周期管理

5.1 创建时机

// 1. 显式创建
@autoreleasepool {// 代码块
}// 2. RunLoop 相关
void _wrapRunLoopWithAutoreleasePool(void) {@autoreleasepool {// RunLoop 逻辑}
}

5.2 释放时机

// 1. @autoreleasepool 块结束
{void *token = objc_autoreleasePoolPush();// ... objc_autoreleasePoolPop(token);
}// 2. RunLoop 迭代结束
void _runLoopIterationDidEnd() {objc_autoreleasePoolPop(currentPool);
}

6. 内存管理

6.1 页面管理

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 溢出处理

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

7. 特殊情况处理

7.1 嵌套池

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

7.2 异常处理

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

8. 性能优化

8.1 快速路径

static inline id autorelease(id obj) {ASSERT(obj);id *dest __unused = autoreleaseFast(obj);return obj;
}

8.2 空间优化

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

9. 最佳实践

9.1 手动管理

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

9.2 子线程处理

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

10. 注意事项

1. 内存峰值:

// 不好的做法
for (int i = 0; i < largeNumber; i++) {// 创建autorelease对象
}  // 在循环结束才释放// 好的做法
for (int i = 0; i < largeNumber; i++) {@autoreleasepool {// 创建autorelease对象}  // 每次迭代都释放
}

2. 线程安全:

// 每个线程维护自己的autoreleasepool栈
+ (void)threadEntryPoint {@autoreleasepool {// 线程代码}
}

3. RunLoop关系:

// 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)

http://www.lryc.cn/news/517519.html

相关文章:

  • 1.CSS的复合选择器
  • 优质内容在个人IP运营中的重要性:以开源AI智能名片商城小程序为应用实例的深度探讨
  • Kafka性能测试
  • 解决Docker冲突问题
  • 新手入门 React .tsx 项目:从零到实战
  • 基于可信数据空间的企业数据要素与流通体系建设(附ppt 下载)
  • 二维数组:求最大元素及其所在的行坐标及列坐标(PTA)C语言
  • WebRtc01: 课程导学、框架介绍
  • HQChart使用教程30-K线图如何对接第3方数据44-DRAWPIE数据结构
  • 【cuda学习日记】2.2 使用2维网络(grid)和2维块(block)对矩阵进行求和
  • 深度学习中CUDA环境安装教程
  • IDEA的常用设置
  • 【VUE+ElementUI】通过接口下载blob流文件设置全局Loading加载进度
  • 算法的五个重要特性和4个基本标准
  • svelte5中使用react组件
  • iOS - 自定义引用计数(MRC)
  • 北航现实场景无人机VLN新基准! OpenUAV:面向真实环境的无人机视觉语言导航,平台、基准与方法
  • OpenCV计算机视觉 08 图像的旋转
  • C++感受15-Hello STL 泛型启蒙
  • 【Java 学习】对象赋值的艺术:Java中clone方法的浅拷贝与深拷贝解析,教你如何在Java中实现完美复制
  • 基于高斯混合模型的数据分析及其延伸应用(具体代码分析)
  • 无人机+Ai应用场景!
  • 操作手册:集成钉钉审批实例消息监听配置
  • AI大模型-提示工程学习笔记4
  • Vue3.5 企业级管理系统实战(一):项目初始搭建与配置
  • 缓存-Redis-缓存更新策略-主动更新策略-Cache Aside Pattern(全面 易理解)
  • 杭州市有哪些大学能够出具论文检索报告?
  • SpringBootWeb 登录认证(day12)
  • 使用AOP在切面逻辑中无法获取到requesetBody
  • 生成模型:变分自编码器-VAE