Person
類繼承自NSObject
, 在main
函數中代碼以下cd
到main.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
函數入手objc_autoreleasePoolPush
函數的底層實現objc_autoreleasePoolPop
函數的底層實現objc_autoreleasePoolPush
和objc_autoreleasePoolPop
, 都是用了AutoreleasePoolPage
AutoreleasePoolPage
中的主要成員變量自動釋放池的主要底層數據結構是:__AtAutoreleasePool、AutoreleasePoolPage
調用了autorelease的對象最終都是經過AutoreleasePoolPage對象來管理的ios
AutoreleasePoolPage
對象佔用4096字節內存,除了用來存放它內部的成員變量,剩下的空間用來存放autorelease
對象的地址AutoreleasePoolPage
中除了一開始的56
個字節用來存儲成員變量, 其餘的全部內存空間都是用來存儲被autorelease
對象的地址begin
和end
兩個函數的實現以下begin = AutoreleasePoolPage地址 + AutoreleasePoolPage的大小
end = AutoreleasePoolPage地址 + SIZE(4096)緩存
AutoreleasePoolPage
不夠存儲autorelease
對象地址時, 就會在建立一個AutoreleasePoolPage
AutoreleasePoolPage
對象經過雙向鏈表的形式鏈接在一塊兒調用push
方法會將一個POOL_BOUNDARY
入棧,而且返回其存放的內存地址bash
調用pop
方法時傳入一個POOL_BOUNDARY
的內存地址,會從最後一個入棧的對象開始發送release
消息,直到遇到這個POOL_BOUNDARY
數據結構
id *next
指向了下一個能存放autorelease
對象地址的區域iphone
能夠經過如下私有函數來查看自動釋放池的狀況 extern void _objc_autoreleasePoolPrint(void);
函數
使用_objc_autoreleasePoolPrint
函數, 查看一個空的autoreleasepool
oop
autorelease
對象page
中有兩個緩存, 其中一個POOL
就是POOL_BOUNDARY
, 第二個就是加入的Person
對象page
中存儲三個內容, 一個POOL_BOUNDARY
, 兩個Person
對象@autoreleasepool
, 代碼以下page
中存儲了兩個POOL_BOUNDARY
@autoreleasepool
, 代碼以下page
中存儲了三個POOL_BOUNDARY
@autoreleasepool
存放1000
個Person
的autorelease
對象page
存儲空間用滿了, 會再次建立一個page
Runloop
中註冊了2個Observer
Observer
監聽了kCFRunLoopEntry
事件,會調用objc_autoreleasePoolPush()
Observer
kCFRunLoopBeforeWaiting
事件,會調用objc_autoreleasePoolPop()、objc_autoreleasePoolPush()
kCFRunLoopBeforeExit
事件,會調用objc_autoreleasePoolPop()