iOS進階教程:處理1000張圖片的記憶體最佳化

來源:互聯網
上載者:User

標籤:

一、項目需求

在實際項目中,使用者在上傳圖片時,有時會一次性上傳大量的圖片。在上傳圖片前,我們要進行一系列操作,比如:旋轉圖片為正確方向,壓縮圖片等,這些操作需要將圖片載入到記憶體中,下面對記憶體的使用做詳細分析.

 二、記憶體分析,非最佳化

我在測試專案中,重複載入了一張圖片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會在一個事件周期(或事件迴圈迭代)的開端—比如滑鼠按下事件—自動建立一個自動釋放池,並且在事件周期的結尾釋放它,因此您的代碼通常不必關心。 有三種情況您應該使用您自己的自動釋放池:

  • 如果您正在編寫一個不是基於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張圖片的記憶體最佳化

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.