我們都知道iOS的內(nèi)存管理分為手動內(nèi)存管理(MRC)和自動內(nèi)存管理(ARC)橙喘,但是不管是手動內(nèi)存管理還是自動內(nèi)存管理,自動釋放池在其中都起到至關(guān)重要的作用
我們首先看下官方文檔對自動釋放池的定義:
An object that supports Cocoa’s reference-counted memory management system.
從官方的定義中我們可以知道谚中,自動釋放池就是一個系統(tǒng)OC對象渴杆,它是作用于內(nèi)存管理中
下面我們先來分析官方文檔中對自動釋放池的一些解釋說明,這樣對我們深刻理解自動釋放池的工作原理非常有幫助
我們先來看下官方對自動釋放池的聲明:
@interface NSAutoreleasePool : NSObject
在手動內(nèi)存管理和自動內(nèi)存管理模式下宪塔,創(chuàng)建自動釋放池的寫法也有所不同,
MRC
模式下
// 創(chuàng)建一個自動釋放池
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSObject *obj = [[NSObject alloc] init];
// 將對象添加到自動釋放池
[obj autorelease];
// 銷毀自動釋放池囊拜,等同于`[pool release];`寫法某筐,但是`[pool release]`和`[pool drain]`又有一些不同,后面會講到不同點
[pool drain];
或者
@autoreleasepool {
NSObject *obj = [[NSObject alloc] init];
// 將對象添加到自動釋放池
[obj autorelease];
}
ARC
模式下
@autoreleasepool {
NSObject *obj = [[NSObject alloc] init];
// 將對象添加到自動釋放池
[obj autorelease];
}
從上面的創(chuàng)建方式我們可以看到冠跷,在ARC模式下南誊,只能使用@autoreleasepool{}
這種方式創(chuàng)建自動釋放池,而不能使用NSAutoreleasePool
這種創(chuàng)建OC對象的方式來創(chuàng)建
關(guān)于自動釋放池的創(chuàng)建方式蜜托,官方文檔也有詳細的介紹說明:
Important
If you use Automatic Reference Counting (ARC), you cannot use autorelease pools directly. Instead, you use @autoreleasepool blocks. For example, in place of:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Code benefitting from a local autorelease pool.
[pool release];
you would write:
@autoreleasepool {
// Code benefitting from a local autorelease pool.
}
@autoreleasepool blocks are more efficient than using an instance of NSAutoreleasePool directly; you can also use them even if you do not use ARC.
在自動釋放池的工作原理中抄囚,只有對象調(diào)用了autorelease
方法,那么這個對象才會被添加到自動釋放池中橄务,然后當這個自動釋放池調(diào)用drain
方法銷毀的時候幔托,便會向池中的每一個對象發(fā)送一條release
消息來銷毀池中的對象,如果一個對象調(diào)用了autorelease
多次,那么在自動釋放池銷毀后會向這個對象發(fā)送多條release
消息來銷毀這個對象重挑,也就是說對象調(diào)用多少次autorelease
嗓化,對象銷毀時就會調(diào)用多少次release
這里說明下一個對象調(diào)用release
和調(diào)用autorelease
的區(qū)別:
如果一個對象調(diào)用release
則會立即釋放(如果引用計數(shù)減為0),如果一個對象調(diào)用autorelease
則會先將這個對象放入自動釋放池谬哀,等到自動釋放池銷毀的時候在釋放這個對象刺覆。也就是說對象調(diào)用autorelease
會延遲釋放
對應于官方文檔的解釋說明如下:
In a reference-counted environment (as opposed to one which uses garbage collection), an NSAutoreleasePool object contains objects that have received an autorelease message and when drained it sends a release message to each of those objects. Thus, sending autorelease instead of release to an object extends the lifetime of that object at least until the pool itself is drained (it may be longer if the object is subsequently retained). An object can be put into the same pool several times, in which case it receives a release message for each time it was put into the pool.
在引用計數(shù)的內(nèi)存管理方式下,Cocoa
框架希望總是有一個自動釋放池可用史煎,如果沒有可用的自動釋放池谦屑,那么自動釋放的的對象得不到釋放就會造成內(nèi)存泄漏
對應于官方文檔的解釋說明如下:
In a reference counted environment, Cocoa expects there to be an autorelease pool always available. If a pool is not available, autoreleased objects do not get released and you leak memory. In this situation, your program will typically log suitable warning messages.
我們都知道iOS的應用程序,在程序一啟動的main
函數(shù)中就創(chuàng)建了一個自動釋放池篇梭,并且在程序的主線程中添加了runloop
氢橙,并且在runloop
的每一個事件循環(huán)開始之前都會去創(chuàng)建自動釋放池,當自動釋放池對象調(diào)用drains
時便會銷毀這個自動釋放池很洋,從而釋放在runloop
處理事件過程中生成的所有對象充蓝。正是因為在runloop
的事件循環(huán)中會自動創(chuàng)建自動釋放池,所以我們在平時開發(fā)過程中也不太需要開發(fā)者來手動創(chuàng)建自動釋放池喉磁,但是如果應用在runloop
事件循環(huán)中創(chuàng)建了大量的臨時自動釋放對象谓苟,那么這時我們最好手動創(chuàng)建自動釋放池,將這大量的臨時對象放到手動創(chuàng)建的自動釋放池中
對應于官方文檔的解釋說明如下:
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. If you use the Application Kit, you therefore typically don’t have to create your own pools. If your application creates a lot of temporary autoreleased objects within the event loop, however, it may be beneficial to create “l(fā)ocal” autorelease pools to help to minimize the peak memory footprint.
這里需要注意:使用[[NSAutoreleasePool alloc] init]
這種方式創(chuàng)建的自動釋放池對象协怒,我們不能對這個自動釋放池對象調(diào)用retain
進行持有涝焙,我們也不能調(diào)用autorelease
來釋放這個自動釋放池對象,我們要想銷毀這個自動釋放池對象孕暇,我們只能調(diào)用drain
或者release
仑撞。但是對于使用@autoreleasepool {}
方式創(chuàng)建的自動釋放池,它會在出了作用域后自動銷毀創(chuàng)建的池子妖滔,不需要開發(fā)者的去調(diào)用函數(shù)銷毀
對應于官方文檔的解釋說明如下:
You create an NSAutoreleasePool object with the usual alloc and init messages and dispose of it with drain (or release—to understand the difference, see Garbage Collection). Since you cannot retain an autorelease pool (or autorelease it—see retain and autorelease), draining a pool ultimately has the effect of deallocating it. You should always drain an autorelease pool in the same context (invocation of a method or function, or body of a loop) that it was created. See Using Autorelease Pool Blocks for more details.
我們都知道在程序的運行過程中隧哮,可能會創(chuàng)建很多的自動釋放池,這些自動釋放池在應用程序中是以棧的方式來進行維護和管理的座舍,新創(chuàng)建的自動釋放池會添加到棧的頂部沮翔,當需要銷毀池子時,就從棧頂移除曲秉。并且每個線程都維護自己的自動釋放池棧采蚀,程序的主線程中有系統(tǒng)創(chuàng)建的自動釋放池,但是新創(chuàng)建的子線程默認是沒有自動釋放池的承二,如果子線程中需要自動釋放池榆鼠,則需要在子線程中手動創(chuàng)建自動釋放池,當子線程銷毀時亥鸠,也會自動銷毀子線程中創(chuàng)建的所有自動釋放池妆够。
對應于官方文檔的解釋說明如下:
Each thread (including the main thread) maintains its own stack of NSAutoreleasePool objects (see Threads). As new pools are created, they get added to the top of the stack. When pools are deallocated, they are removed from the stack. Autoreleased objects are placed into the top autorelease pool for the current thread. When a thread terminates, it automatically drains all of the autorelease pools associated with itself.
自動釋放池與線程之間的關(guān)系,官方文檔說明如下:
Threads
If you are making Cocoa calls outside of the Application Kit’s main thread—for example if you create a Foundation-only application or if you detach a thread—you need to create your own autorelease pool.
If your application or thread is long-lived and potentially generates a lot of autoreleased objects, you should periodically drain and create autorelease pools (like the Application Kit does on the main thread); otherwise, autoreleased objects accumulate and your memory footprint grows. If, however, your detached thread does not make Cocoa calls, you do not need to create an autorelease pool.
Note
If you are creating secondary threads using the POSIX thread APIs instead of NSThread objects, you cannot use Cocoa, including NSAutoreleasePool, unless Cocoa is in multithreading mode. Cocoa enters multithreading mode only after detaching its first NSThread object. To use Cocoa on secondary POSIX threads, your application must first detach at least one NSThread object, which can immediately exit. You can test whether Cocoa is in multithreading mode with the NSThread class method isMultiThreaded.
自動釋放池對象調(diào)用drain
或release
來銷毀池子,它們二者的區(qū)別:
如果只是在引用計數(shù)環(huán)境下责静,那么調(diào)用drain
和調(diào)用release
功能上是一樣的袁滥,但是如果在垃圾回收(GC)環(huán)境下,調(diào)用release
等于是一個no-op
操作灾螃,no-op
操作可以理解為沒有操作計算機指令题翻,而調(diào)用drain
則會發(fā)出一個objc_collect_if_needed
的GC操作。
所以說當我們不清楚什么時候會有GC操作時腰鬼,這時我們最好選擇使用drain
來銷毀自動釋放池是最為安全的嵌赠。
對應于官方文檔的解釋說明如下:
Garbage Collection
In a garbage-collected environment, there is no need for autorelease pools.
You may, however, write a framework that is designed to work in both a
garbage-collected and reference-counted environment. In this case, you can use
autorelease pools to hint to the collector that collection may be appropriate.
In a garbage-collected environment, sending a drain message to a pool triggers
garbage collection if necessary; release, however, is a no-op. In a reference-
counted environment, drain has the same effect as release. Typically,
therefore, you should use drain instead of release.
上面我們對iOS的自動釋放池NSAutoreleasePool
的官方文檔說明進行了理論性的分析和總結(jié),下面我們就從底層源碼來分析自動釋放池的底層結(jié)構(gòu)和實現(xiàn)原理
講解示例Demo地址:
https://github.com/guangqiang-liu/11-AutoreleasePool
https://github.com/guangqiang-liu/11.1-AutoreleasePool
https://github.com/guangqiang-liu/11.2-AutoreleasePool
https://github.com/guangqiang-liu/11.3-AutoreleasePool
更多文章
- ReactNative開源項目OneM(1200+star):https://github.com/guangqiang-liu/OneM:歡迎小伙伴們 star
- iOS組件化開發(fā)實戰(zhàn)項目(500+star):https://github.com/guangqiang-liu/iOS-Component-Pro:歡迎小伙伴們 star
- 簡書主頁:包含多篇iOS和RN開發(fā)相關(guān)的技術(shù)文章http://www.reibang.com/u/023338566ca5 歡迎小伙伴們:多多關(guān)注熄赡,點贊
- ReactNative QQ技術(shù)交流群(2000人):620792950 歡迎小伙伴進群交流學習
- iOS QQ技術(shù)交流群:678441305 歡迎小伙伴進群交流學習