ARC的原理详解
1,ARC的本質
ARC本質是NSAutoreleasePool的直接應用,
@autorelease{
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
其實是:
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
int iRet =?UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
[pool release];
然后,各種allocrelease后,對應refcount都設置成0,在出自己的引用范圍后,就背nsautoreleasepool自動的釋放掉,如下:
NSString* str = [[[NSString alloc] init] autorelease];
.......
其中str已經進行了autorelease,當結束生命周期后,str直接釋放掉。
2,NSAutoreleasePool的原理
AutoreleasePoolPage是一個C++實現的類。
typedef struct{ magic_t const magic; id* next; pThread_t* thread; AutoreleasePoolPage* Parent; AutoreleasePoolPage* Child; uint32_t const depth; uint32_t hiwat; } 其中: 1,magic是魔術數字,劃分內存邊界,數據結構起始處; 2,next,是指向該AutoreleasePool的邊界; 3,thread, 是該AutoreleasePool的線程,每個線程有自己的AutoreleasePool; 4,Parent、child,用于建立鏈表,一個AutoreleasePool不一定足夠; 每個NSAutoreleasePool都是4096bytes,不夠的就申請新的NSAutoreleasePool,用child, parent連接起來,見上圖: 1,“類實例所占內存”就是數據接口NSAutoreleasePool的空間; 2,“id objx”, 就是各個申請的對象指針; 3,next,指的是堆棧頂處; 對象是如何申請的?圖中的情況,這一頁再加入一個autorelease對象就要滿了(也就是next指針馬上指向棧頂),這時就要執行上面說的操作,建立下一頁page對象,與這一頁鏈表連接完成后,新page的next指針被初始化在棧底(begin的位置),然后繼續向棧頂添加新對象。
所以,向一個對象發送- autorelease消息,就是將這個對象加入到當前AutoreleasePoolPage的棧頂next指針指向的位置
對象是如何釋放的? 每當進行一次objc_autoreleasePoolPush調用時,runtime向當前的AutoreleasePoolPage中add進一個哨兵對象,值為0(也就是個nil),那么這一個page就變成了下面的樣子:objc_autoreleasePoolPush的返回值正是這個哨兵對象的地址,被objc_autoreleasePoolPop(哨兵對象)作為入參,于是:
1.根據傳入的哨兵對象地址找到哨兵對象所處的page
2.在當前page中,將晚于哨兵對象插入的所有autorelease對象都發送一次- release消息,并向回移動next指針到正確位置
3.補充2:從最新加入的對象一直向前清理,可以向前跨越若干個page,直到哨兵所在的page
剛才的objc_autoreleasePoolPop執行后,最終變成了下面的樣子:
嵌套的AutoreleasePool
知道了上面的原理,嵌套的AutoreleasePool就非常簡單了,pop的時候總會釋放到上次push的位置為止,多層的pool就是多個哨兵對象而已,就像剝洋蔥一樣,每次一層,互不影響。
?
轉載于:https://www.cnblogs.com/runner42/p/5031154.html
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
- 上一篇: 自定义View,圆形头像
- 下一篇: 关于“无法完成该动作 到Microsof