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)