標籤:
一、項目需求
在實際項目中,使用者在上傳圖片時,有時會一次性上傳大量的圖片。在上傳圖片前,我們要進行一系列操作,比如:旋轉圖片為正確方向,壓縮圖片等,這些操作需要將圖片載入到記憶體中,下面對記憶體的使用做詳細分析.
二、記憶體分析,非最佳化
我在測試專案中,重複載入了一張圖片1000次,首先載入圖片到記憶體,然後進行壓縮操作,釋放記憶體
| 12345678910111213141516171819 |
for (int i = 0; i <= 1000; i ++) { //1.首先我們擷取到需要處理的圖片資源的路徑 NSString *filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"PNG"]; //2.將圖片載入到記憶體中,我們使用了alloc關鍵字,在使用完後,可以手動快速釋放掉記憶體 UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath]; //3.這一步我們將圖片進行了壓縮,並得到一個autorelease類型執行個體 UIImage *image2 = [image imageByScalingAndCroppingForSize:CGSizeMake(480, 320)]; //4.釋放掉2步驟的記憶體 [image release]; } |
上面的代碼看起來沒有任何問題,可以說是一種標準的代碼寫法,在每一步驟中都對記憶體做了小心的處理,我們來看一下,實際的記憶體使用量情況:
在中可以看到,我們的操作在沒有任何問題的情況下,在載入大量圖片時,還是會造成記憶體的劇減
可以看到自動釋放記憶體時,圖片佔用的記憶體並沒有立即釋放掉
這些資源沒有立即釋放的資源,佔用了寶貴的記憶體資源,最終使程式被kill
三最佳化後的記憶體使用量
上面程式被kill,是因為程式的記憶體使用量問題,在上面的代碼中,我們每一步都對記憶體做了非常小心的處理,但是在載入大量的圖片時,還是會出現問題。其根本原因就是autorelease惹的禍,autorelease自動釋放記憶體,並不會立即把記憶體釋放掉,而是要等到下一個事件周期才會釋放掉。問題是一些資源我們不得不使用autorelease類型,比如作為函數的傳回值,而且系統api及項目是的大部分也都是這麼做的,如果全都依靠我們手動釋放很容易造成記憶體流失。
| 12345678910111213141516171819 |
for (int i = 0; i <= 1000; i ++) { //建立一個自動釋放池 NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSString *filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"PNG"]; UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath]; UIImage *image2 = [image imageByScalingAndCroppingForSize:CGSizeMake(480, 320)]; [image release]; //將自動釋放池記憶體釋放,它會同時釋放掉上面代碼中產生的臨時變數image2 [pool drain]; } |
最佳化後的,記憶體使用量情況
可用記憶體不再明顯的減少
CGImage及UIImage的資料由原來的220多減少到6-7個
可以看到使用了 NSAutoreleasePool後,載入大量圖片的時候記憶體也不會出現問題
四、自動釋放池概述
(1)自動釋放池被置於一個堆棧中,雖然它們通常被稱為被“嵌套”的。當您建立一個新的自動釋放池時,它被添加到堆棧的頂部。當自動釋放池被回收時,它們從堆棧中被刪除。當一個對象收到送autorelease訊息時,它被添加到當前線程的目前處於棧頂的自動釋放池中。你不能向自動釋放池發送autorelease或retain訊息。Application Kit會在一個事件周期(或事件迴圈迭代)的開端—比如滑鼠按下事件—自動建立一個自動釋放池,並且在事件周期的結尾釋放它,因此您的代碼通常不必關心。 有三種情況您應該使用您自己的自動釋放池:
(2) release和drain之間的差異
在引用計數環境下,release和drain一樣,會直接自動釋放池l對象。
在GC(記憶體回收)環境下,release是一個no-op(空操作),drain會觸發記憶體回收(如果自上次記憶體回收以來分配的記憶體大於當前的閾值)。
通常情況下,您都應該使用drain而不是使用release來銷毀自動釋放池。
-drain方法只適用於Mac OS X10.4(Tiger)及更高版本。
在OS X Mountain Lion v10.8作業系統下,GC(記憶體回收)將被廢棄,ARC(Automatic Reference Counting自動引用計數)為推薦的替代技術。
iOS進階教程:處理1000張圖片的記憶體最佳化