iOS —— AutoreleasePool

首先:autorelease 的本質就是延時調用release;

AutoreleasePool創建和釋放

App啓動後,蘋果在主線程 RunLoop 裏註冊了兩個 Observer,其回調都是 _wrapRunLoopWithAutoreleasePoolHandler()。

第一個 Observer 監視的事件是 Entry(即將進入Loop),其回調內會調用 _objc_autoreleasePoolPush() 創建自動釋放池。其 order 是-2147483647,優先級最高,保證創建釋放池發生在其他所有回調之前。

第二個 Observer 監視了兩個事件: BeforeWaiting(準備進入休眠) 時調用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 釋放舊的池並創建新池;Exit(即將退出Loop) 時調用 _objc_autoreleasePoolPop() 來釋放自動釋放池。這個 Observer 的 order 是 2147483647,優先級最低,保證其釋放池子發生在其他所有回調之後。

在主線程執行的代碼,通常是寫在諸如事件回調、Timer回調內的。這些回調會被 RunLoop 創建好的 AutoreleasePool 環繞着,所以不會出現內存泄漏,開發者也不必顯示創建 Pool 了。

也就是說AutoreleasePool創建是在一個RunLoop事件開始之前(push),AutoreleasePool釋放是在一個RunLoop事件即將結束之前(pop)。
AutoreleasePool裏的Autorelease對象的加入是在RunLoop事件中,AutoreleasePool裏的Autorelease對象的釋放是在AutoreleasePool釋放時。

 

自動釋放池的主要結構體和類是:_AtAutoreleasePool、AutoreleasePoolPage;

調用了autorelease的對象最終都是通過AutoreleasePoolPage對象類管理的;

AutoreleasePoolPage的的大小都是4096個字節;

 

自動釋放池是有AutoreleasePoolPage以雙向鏈表的方式實現的;

當對象調用Autorelease的方法時,會將延時釋放的對象加入AutoreleasePoolPage中;

調用pop方法時,會向棧中發送release消息;

 

NSAutoreleasePool何時釋放?

當別人問你NSAutoreleasePool何時釋放?你回答“當前作用域大括號結束時釋放”,顯然木有正確理解Autorelease機制。
在沒有手加Autorelease Pool的情況下,Autorelease對象是在當前的runloop迭代結束時釋放的,而它能夠釋放的原因是系統在每個runloop迭代中都加入了自動釋放池Push和Pop

NSThread、NSRunLoop 和 NSAutoreleasePool

根據蘋果官方文檔中對 NSRunLoop的描述,我們可以知道每一個線程,包括主線程,都會擁有一個專屬的 NSRunLoop 對象,並且會在有需要的時候自動創建。

Each NSThread object, including the application’s main thread, has an NSRunLoop object automatically created for it as needed.

同樣的,根據蘋果官方文檔中對 NSAutoreleasePool的描述,我們可知,在主線程的 NSRunLoop 對象(在系統級別的其他線程中應該也是如此,比如通過 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 獲取到的線程)的每個 event loop 開始前,系統會自動創建一個 autoreleasepool ,並在 event loop 結束時 drain 。我們上面提到的場景 1 中創建的 autoreleased 對象就是被系統添加到了這個自動創建的 autoreleasepool 中,並在這個 autoreleasepool 被 drain 時得到釋放。

The Application Kit creates an autorelease pool on the main thread at the beginning of every cycle of the event loop, and drains it at the end, thereby releasing any autoreleased objects generated while processing an event.

另外,NSAutoreleasePool 中還提到,每一個線程都會維護自己的 autoreleasepool 堆棧。換句話說 autoreleasepool 是與線程緊密相關的,每一個 autoreleasepool 只對應一個線程。

Each thread (including the main thread) maintains its own stack of NSAutoreleasePool objects.

弄清楚 NSThread、NSRunLoop 和 NSAutoreleasePool 三者之間的關係可以幫助我們從整體上了解 Objective-C 的內存管理機制,清楚系統在背後到底爲我們做了些什麼,理解整個運行機制等。


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章