一柱彻、項目需求
實際項目中莹汤,用戶在上傳圖片時瓶堕,可能會一次性上傳大量的圖片。上傳圖片前赌渣,我們要進行一系列操作,比如:旋轉(zhuǎn)圖片為正確方向昌犹,壓縮圖片等坚芜,但是這些操作需要將圖片加載到內(nèi)存中,下面對內(nèi)存的使用做詳細(xì)分析.
二斜姥、內(nèi)存分析鸿竖,沒有優(yōu)化
我在項目中,重復(fù)加載了一張圖片1000次疾渴,首先加載圖片到內(nèi)存千贯,然后進行壓縮操作,釋放內(nèi)存
上述的代碼看起來沒有任何問題搞坝,是一種標(biāo)準(zhǔn)的代碼寫法搔谴,每一步驟中都對內(nèi)存做了小心的處理,但是桩撮,實際的內(nèi)存使用情況:
上圖中可以看到敦第,上述的操作在沒有任何問題的情況下峰弹,加載大量圖片時,還是會造成內(nèi)存的飆升芜果。
可以看到自動釋放內(nèi)存時鞠呈,圖片占用的內(nèi)存并沒有立即釋放掉
圖片資源沒有被立即釋放,占用了寶貴的內(nèi)存資源右钾,最終程序被操作系統(tǒng)殺死蚁吝。
三、 優(yōu)化后的內(nèi)存使用
上面程序被操作系統(tǒng)殺死舀射,是因為程序的內(nèi)存使用問題窘茁,在上面的代碼中,我們每一步都對內(nèi)存做了非常小心的處理脆烟,但是在加載大量的圖片時山林,還是會出現(xiàn)問題。其根本原因就是autorelease的問題邢羔,autorelease自動釋放內(nèi)存驼抹,但是并不會立即把內(nèi)存釋放掉,而是需 要等到下一個事件周期才會釋放掉拜鹤。問題是一些資源我們不得不使用autorelease類型框冀,比如作為函數(shù)的返回值,而且系統(tǒng)api及項目是的大部分也都是這么做的署惯,如果全都依靠我們手動釋放很容易造成內(nèi)存泄漏左驾。
優(yōu)化后的,內(nèi)存的實際使用情況极谊。
可用內(nèi)存不再急劇下降诡右。
CGImage及UIImage的數(shù)量由原來的220多減少到7個。
可以看到使用了NSAutoreleasePool后轻猖,加載大量圖片的時候內(nèi)存也不會出現(xiàn)問題帆吻。
四、自動釋放池概述
1. 自動釋放池被置于一個堆棧中咙边,雖然它們通常被稱為被“嵌套”的猜煮。創(chuàng)建一個新的自動釋放池時,它被添加到堆棧的頂部败许。當(dāng)自動釋放池被回收時王带,它從堆棧中被刪除。當(dāng)一個對象收到系統(tǒng)的autorelease消息時市殷,它被添加到當(dāng)前線程的目前處于棧頂?shù)淖詣俞尫懦刂秀底3绦騿T不能向自動釋放池發(fā)送autorelease或retain消息。Application Kit會在一個事件周期(或事件循環(huán)迭代)的開端—比如點擊屏幕事件—自動創(chuàng)建一個自動釋放池,并且在事件周期的結(jié)尾釋放它搞挣,因此代碼通常不必關(guān)心釋放問題带迟。但是以下三種情況需要自己創(chuàng)建的自動釋放池:
一個不是基于Application Kit的程序,比如命令行工具囱桨,則沒有對自動釋放池的內(nèi)置支持仓犬;需要自己創(chuàng)建它們。
一個異步線程舍肠,一旦該線程開始執(zhí)行搀继,需要立即創(chuàng)建自動釋放池;否則貌夕,將會泄漏對象律歼。
一個循環(huán),其中創(chuàng)建了許多臨時對象啡专,可以在循環(huán)內(nèi)部創(chuàng)建一個自動釋放池,以便在下次迭代之前銷毀這些臨時對象制圈。自動釋放池可以幫助減少應(yīng)用程序的最大內(nèi)存占用量们童。
2. release和drain之間的差異
在引用計數(shù)環(huán)境下,release和drain一樣,會直接自動釋放對象鲸鹦。
在GC(垃圾回收)環(huán)境下慧库,release是一個no-op(空操作),drain會觸發(fā)垃圾回收(如果自上次垃圾回收以來分配的內(nèi)存大于當(dāng)前的閾值)馋嗜。
通常情況下齐板,需要使用drain而不是使用release銷毀自動釋放池。
-drain方法只適用于Mac OS X10.4(Tiger)及更高版本葛菇。