iOS 使用Instruments優化內存性能

iOS 使用Instruments優化內存性能ios

問題

項目中使用到圖片合成視頻,發現內存增加十分的迅速,致使一些由於內存引發的問題,本文使用這個案例,結合Instruments工具檢測和分析問題,最終解決內存問題。git

本文的Demo代碼 ScreenRecorderTest2app

Instruments檢測

查看某個範圍內的內存增加ide

  1. 打開Instruments選擇Allocations工具,點擊錄製按鈕進行錄製
  2. 使用鼠標框選出內存增加的區域,圖中兩條黑線中的高亮區域

查看某個範圍內的內存增加函數

  • 上面圖表區域是內存的可視化視圖
  • 下面的面板區域顯示的是具體的統計數據
    能夠看到總體的內存增加爲16.81M (All Heap Allocations 堆內存的分配)

堆內存分配的詳細統計數據
點擊All Heap Allocations旁邊的小箭頭按鈕能夠看堆內存分配的詳細統計數據: 堆內存分配的詳細統計數據工具

  • Address:數據的內存地址
  • Timestamp:數據建立的時間
  • Size:數據的大小
  • Responsible Library:數據建立的相關的庫
  • Responsible Caller:數據建立的相關的庫的函數調用

統計數據表中能夠看出AppleJPEG 庫調用 applejpeg_decode_create 方法建立了不少的內存的數據

 右邊區域顯示的是函數的調用棧信息面板(Stack Trace),右上角的工字型按鈕能夠切換顯示系統函數調用
切換顯示系統函數調用性能

內存分配大小與對應的代碼調用信息的可視化顯示
點擊調用棧中的高亮代碼能夠查看代碼詳情和內存信息:
內存分配大小與對應的代碼調用信息的可視化顯示優化

右邊的標註區域顯示的是內存佔用的比例。code

分析

上圖中看到buffer對象和image佔用的內存最大,可是buffer在每次使用以後都會調用CVPixelBufferRelease釋放對應的內存,不會有內存的問題,image對象釋放的不及時,會在整個while循環塊中保留一段時間,致使內存的增加。
此外image對象釋放不及時和在在同一時間調用CVPixelBufferRelease(buffer);釋放buffer也有關係,若是沒有建立buffer和釋放buffer的操做,image對象的增加也不會很明顯,釋放的速度也挺快,下面兩個對照組能夠進行對比分析視頻

對照組1:只有在循環中建立image對象內存增加:
內存增加爲2.73M
對照組1:只有在循環中建立image對象內存增加:

對照組2:在循環中添加autoreleasepool建立image對象內存增加:
內存增加爲492K
對照組2:在循環中添加autoreleasepool建立image對象內存增加

由上可知,使用autoreleasepool能夠有效的解決在某個循環中建立大量的內存敏感型對象致使的內存上漲的問題

最終解決方案
在while循環內部使用autoreleasepool塊,每次循環arc對象得以及時的釋放,內存增加從原來的16.81M降低到了只有475K
最終解決方案

代碼:

while(i < imageNames.count) {
    // 添加自動釋放池,讓內存敏感型的對象(UIImage)及時釋放
    @autoreleasepool {
       // 代碼省略...
        NSString *imageName = [imageNames objectAtIndex:i];
        NSString* imagePath = [imageSavedDir stringByAppendingPathComponent:imageName];
        UIImage* image = [UIImage imageWithContentsOfFile:imagePath];
        if(adaptor.assetWriterInput.readyForMoreMediaData) {
            i++;
            CMTime frameTime = CMTimeMake(1, fps);
            CMTime lastTime = CMTimeMake(i, fps);
            CMTime presentTime = CMTimeAdd(lastTime, frameTime);
            
            buffer = [self pixelBufferFromCGImage:[image CGImage] size:videoFrameSize];
            // 寫入視頻
            BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime];
            if(buffer) {
                CVPixelBufferRelease(buffer);
            }
            // 代碼省略...
            [NSThread sleepForTimeInterval:0.05];
        } else {
            NSLog(@"Error: Adaptor is not ready");
            [NSThread sleepForTimeInterval:0.05];
            i--;
        }
    }
}

總結

以上是使用Instruments解決內存問題的總結,若有不妥之處還請不吝賜教
本文的Demo代碼 ScreenRecorderTest2

相關文章
相關標籤/搜索