小码哥iOS学习笔记第二十六天: @autoreleasepool

1、@autoreleasepool编译后的代码

  • 定义Person类继承自NSObject, 在main函数中代码以下

  • 经过终端cdmain.m所在文件夹, 并执行下面的命令
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m
复制代码
  • 将生成的main.cpp文件拖到项目中并打开, 能够找到main.m文件在底层的代码

  • 整理后, 就是下面的代码

  • 搜索__AtAutoreleasePool结构体

  • 整理后以下

  • 咱们知道, 一个自动释放池会自动销毁, 因此main函数中的代码能够模拟为下图所示

  • 因此, 想要了解@autoreleasepool, 能够从objc_autoreleasePoolPush函数和objc_autoreleasePoolPop函数入手

2、objc_autoreleasePoolPush 和 objc_autoreleasePoolPop

  • objc_autoreleasePoolPush函数的底层实现

  • objc_autoreleasePoolPop函数的底层实现

  • 能够看到objc_autoreleasePoolPushobjc_autoreleasePoolPop, 都是用了AutoreleasePoolPage
  • 下图中展现的是AutoreleasePoolPage中的主要成员变量

自动释放池的主要底层数据结构是:__AtAutoreleasePool、AutoreleasePoolPage
调用了autorelease的对象最终都是经过AutoreleasePoolPage对象来管理的ios

3、AutoreleasePoolPage的结构

  • 每一个AutoreleasePoolPage对象占用4096字节内存,除了用来存放它内部的成员变量,剩下的空间用来存放autorelease对象的地址

  • AutoreleasePoolPage中除了一开始的56个字节用来存储成员变量, 其余的全部内存空间都是用来存储被autorelease对象的地址
  • 其中beginend两个函数的实现以下

begin = AutoreleasePoolPage地址 + AutoreleasePoolPage的大小
end = AutoreleasePoolPage地址 + SIZE(4096)缓存

  • 当一个AutoreleasePoolPage不够存储autorelease对象地址时, 就会在建立一个AutoreleasePoolPage
  • 全部的AutoreleasePoolPage对象经过双向链表的形式链接在一块儿

4、AutoreleasePoolPage的push和pop

  • 调用push方法会将一个POOL_BOUNDARY入栈,而且返回其存放的内存地址bash

  • 调用pop方法时传入一个POOL_BOUNDARY的内存地址,会从最后一个入栈的对象开始发送release消息,直到遇到这个POOL_BOUNDARY数据结构

  • id *next指向了下一个能存放autorelease对象地址的区域iphone

  • 能够经过如下私有函数来查看自动释放池的状况 extern void _objc_autoreleasePoolPrint(void);函数

  • 使用_objc_autoreleasePoolPrint函数, 查看一个空的autoreleasepooloop

  • 能够看到, 此时自动缓冲池中并无任何的autorelease对象

  • 添加一个autorelease对象

  • 能够看到page中有两个缓存, 其中一个POOL就是POOL_BOUNDARY, 第二个就是加入的Person对象

  • 再添加一个autorelease对象

  • 此时page中存储三个内容, 一个POOL_BOUNDARY, 两个Person对象

  • 嵌套一层@autoreleasepool, 代码以下

  • 此时能够看到page中存储了两个POOL_BOUNDARY

  • 再次嵌套一层@autoreleasepool, 代码以下

  • 此时能够看到page中存储了三个POOL_BOUNDARY

  • @autoreleasepool存放1000Personautorelease对象

  • 能够看到, 一个page存储空间用满了, 会再次建立一个page

5、Runloop和Autorelease

  • iOS在主线程的Runloop中注册了2个Observer
  • 第1个Observer监听了kCFRunLoopEntry事件,会调用objc_autoreleasePoolPush()
  • 第2个Observer
  • 监听了kCFRunLoopBeforeWaiting事件,会调用objc_autoreleasePoolPop()、objc_autoreleasePoolPush()
  • 监听了kCFRunLoopBeforeExit事件,会调用objc_autoreleasePoolPop()
相关文章
相关标签/搜索