iOS 使用Instruments优化内存性能

iOS 使用Instruments优化内存性能

问题

项目中使用到图片合成视频,发现内存增长十分的迅速,导致一些因为内存引起的问题,本文使用这个案例,结合Instruments工具检测和分析问题,最终解决内存问题。

本文的Demo代码 ScreenRecorderTest2

Instruments检测

查看某个范围内的内存增长

  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),右上角的工字型按钮可以切换显示系统函数调用
切换显示系统函数调用

内存分配大小与对应的代码调用信息的可视化显示
点击调用栈中的高亮代码可以查看代码详情和内存信息:
内存分配大小与对应的代码调用信息的可视化显示

右边的标注区域显示的是内存占用的比例。

分析

上图中看到buffer对象和image占用的内存最大,但是buffer在每次使用之后都会调用CVPixelBufferRelease释放对应的内存,不会有内存的问题,image对象释放的不及时,会在整个while循环块中保留一段时间,导致内存的增长。
此外image对象释放不及时和在在同一时间调用CVPixelBufferRelease(buffer);释放buffer也有关系,如果没有创建buffer和释放buffer的操作,image对象的增长也不会很明显,释放的速度也挺快,下面两个对照组可以进行对比分析

对照组1:只有在循环中创建image对象内存增长:
内存增长为2.73M
对照组1:只有在循环中创建image对象内存增长:

扫描二维码关注公众号,回复: 19782 查看本文章

对照组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

猜你喜欢

转载自my.oschina.net/FEEDFACF/blog/1620259