1. 程式人生 > 實用技巧 >IOS高階教程1:處理1000張圖片的記憶體優化

IOS高階教程1:處理1000張圖片的記憶體優化

轉載請保留以下原文連結:

http://my.oschina.net/taptale/blog/91894

一、專案需求

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

二、記憶體分析,非優化

我在測試專案中,重複載入了一張圖片1000次,首先載入圖片到記憶體,然後進行壓縮操作,釋放記憶體

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及專案是的大部分也都是這麼做的,如果全都依靠我們手動釋放很容易造成記憶體洩漏。

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自動引用計數)為推薦的替代技術。

來源:大良網站建設