1313## 从 main 函数开始
1414
1515` main ` 函数可以说是在整个 iOS 开发中非常不起眼的一个函数,它很好地隐藏在 ` Supporting Files ` 文件夹中,却是整个 iOS 应用的入口。
16- ![ objc-autorelease-main] ( media/14628459785637 /objc-autorelease-main.png)
16+ ![ objc-autorelease-main] ( ../images /objc-autorelease-main.png)
1717
1818` main.m ` 文件中的内容是这样的:
1919
@@ -39,7 +39,7 @@ $ clang -rewrite-objc main.m
3939
4040在生成了一大堆警告之后,当前目录下多了一个 ` main.cpp ` 文件
4141
42- ![ objc-autorelease-main-cpp] ( media/14628459785637 /objc-autorelease-main-cpp.png)
42+ ![ objc-autorelease-main-cpp] ( ../images /objc-autorelease-main-cpp.png)
4343
4444> 这里删除了 ` main ` 函数中其他无用的代码。
4545
@@ -53,7 +53,7 @@ $ clang -rewrite-objc main.m
5353
5454在 ` main.cpp ` 中查找名为 ` __AtAutoreleasePool ` 的结构体:
5555
56- ![ objc-autorelease-main-cpp-struct] ( media/14628459785637 /objc-autorelease-main-cpp-struct.png)
56+ ![ objc-autorelease-main-cpp-struct] ( ../images /objc-autorelease-main-cpp-struct.png)
5757
5858``` objectivec
5959struct __AtAutoreleasePool {
@@ -108,7 +108,7 @@ void objc_autoreleasePoolPop(void *ctxt) {
108108
109109` AutoreleasePoolPage ` 是一个 C++ 中的类:
110110
111- ![ objc-autorelease-AutoreleasePoolPage] ( media/14628459785637 /objc-autorelease-AutoreleasePoolPage.png)
111+ ![ objc-autorelease-AutoreleasePoolPage] ( ../images /objc-autorelease-AutoreleasePoolPage.png)
112112
113113它在 ` NSObject.mm ` 中的定义是这样的:
114114
@@ -138,23 +138,23 @@ class AutoreleasePoolPage {
138138
139139自动释放池中的 `AutoreleasePoolPage` 是以**双向链表**的形式连接起来的:
140140
141- 
141+ 
142142
143143> `parent` 和 `child` 就是用来构造双向链表的指针。
144144
145145#### 自动释放池中的栈
146146
147147如果我们的一个 `AutoreleasePoolPage` 被初始化在内存的 `0x100816000 ~ 0x100817000` 中,它在内存中的结构如下:
148148
149- 
149+ 
150150
151151其中有 56 bit 用于存储 `AutoreleasePoolPage` 的成员变量,剩下的 `0x100816038 ~ 0x100817000` 都是用来存储**加入到自动释放池中的对象**。
152152
153153> `begin()` 和 `end()` 这两个类的实例方法帮助我们快速获取 `0x100816038 ~ 0x100817000` 这一范围的边界地址。
154154
155155`next` 指向了下一个为空的内存地址,如果 `next` 指向的地址加入一个 `object`,它就会如下图所示**移动到下一个为空的内存地址中**:
156156
157- 
157+ 
158158
159159> 关于 `hiwat` 和 `depth` 在文章中并不会进行介绍,因为它们并不影响整个自动释放池的实现,也不在关键方法的调用栈中。
160160
@@ -187,7 +187,7 @@ int main(int argc, const char * argv[]) {
187187
188188而当方法 `objc_autoreleasePoolPop` 调用时,就会向自动释放池中的对象发送 `release` 消息,直到第一个 `POOL_SENTINEL`:
189189
190- 
190+ 
191191
192192### <a id='objc_autoreleasePoolPush'></a>objc_autoreleasePoolPush 方法
193193
@@ -315,7 +315,7 @@ void objc_autoreleasePoolPop(void *ctxt) {
315315
316316我们一般都会在这个方法中传入一个哨兵对象 `POOL_SENTINEL`,如下图一样释放对象:
317317
318- 
318+ 
319319
320320#### 对 objc_autoreleasePoolPop 行为的测试
321321
@@ -339,11 +339,11 @@ int main(int argc, const char * argv[]) {
339339
340340在代码的这一行打一个断点,因为这里会调用 ` autorelease ` 方法,将字符串加入自动释放池:
341341
342- ![ objc-autorelease-breakpoint-main] ( media/14628459785637 /objc-autorelease-breakpoint-main.png)
342+ ![ objc-autorelease-breakpoint-main] ( ../images /objc-autorelease-breakpoint-main.png)
343343
344344当代码运行到这里时,通过 lldb 打印出当前 ` hotPage ` 中的栈内容:
345345
346- ![ objc-autorelease-print-pool-content] ( media/14628459785637 /objc-autorelease-print-pool-content.png)
346+ ![ objc-autorelease-print-pool-content] ( ../images /objc-autorelease-print-pool-content.png)
347347
3483481 . 通过 ` static ` 方法获取当前 ` hotPage `
3493492 . 打印 ` AutoreleasePoolPage ` 中的内容
@@ -352,7 +352,7 @@ int main(int argc, const char * argv[]) {
352352
353353然后将字符串 ` @"Draveness-Suffix" ` 的指针传入 ` pop ` 方法,测试 ` pop ` 方法能否传入非哨兵参数。
354354
355- ![ objc-autorelease-pop-string] ( media/14628459785637 /objc-autorelease-pop-string.png)
355+ ![ objc-autorelease-pop-string] ( ../images /objc-autorelease-pop-string.png)
356356
357357再次打印当前 ` AutoreleasePoolPage ` 的内容时,字符串已经不存在了,这说明** 向 ` pop ` 方法传入非哨兵参数是可行的** ,只是我们一般不会传入非哨兵对象。
358358
0 commit comments