来简书的第一篇文章,记录下我来新公司第一天使用insturments解决的SDWebImage引起的内存爆增导致的app闪退。当程序在苹果6上运行时,会不定时闪退,app活不过三秒。全局断点无法捕获,只有关于内存的控制台日志输出,所以就直接上了insturments。
insturments的使用连接设备,使用command+i启动,随后
![](https://img.haomeiwen.com/i4970273/bc9ed2ff6591c9e3.png)
进入面板后点击左上角红色按钮,此时你会看到设备上app已经启动。然后出现下面界面
![](https://img.haomeiwen.com/i4970273/33512b7b7ff0943e.png)
果然内存问题,在此解释下图中三个名称。
All Heap & Anonymous VM:系统为app分配所有内存
All Heap Allocations:App在堆上内存,你可以理解为app真实内存
All Anonymous VM:APP所分配的虚拟内存,关于虚拟内存可以这么理解。当我们程序向系统申请内存时,操作系统并不会直接返回给我们物理地址,而是给虚拟地址,虚拟地址映射物理地址,它就相当于一个桥接,我们程序和真实存储物理地址之间的一个转换器。我们要使用时,向操作系统申请后,我们拿到数据所在物理内存上的一个虚拟地址,转换过程由操作系统管理。操作系统会为我们提前分配足够的空间,并不是一定完全使用。我们下面要说的CG raster data数据就存储在这里。
CG raster data:图片栅格数据。
我们现在可以看我app的问题,图片栅格化数据占用将近800M,苹果6的内存才1个G,所以app是因为内存问题被系统强制杀死了。随后我在Appdelegete中实现了内存警告代理也证实了这个问题。在随后的测试中,在X Max上虚拟内存可以达到1.5个G,基本都是CG raster data占用。点进去看下情况:
![](https://img.haomeiwen.com/i4970273/db3541273066d393.png)
将表切换为树
![](https://img.haomeiwen.com/i4970273/1ac5dca7485392fe.png)
这下可以看到真实的罪魁祸手了
![](https://img.haomeiwen.com/i4970273/013820d744207392.png)
双击可以看到源码,但需要提前在xcode中配置debug information format
![](https://img.haomeiwen.com/i4970273/522b76894e339619.png)
现在可以看哪里出了问题
![](https://img.haomeiwen.com/i4970273/551d9bb5923a735c.png)
到此我知道了问题出在了哪里,通过查找确实SDWebImage出现的问题。其实也不算,只是上个老哥在开发的时候只是使用了,但是忽略了相关配置。产生此问题的原因是SDWebImage中为了app使用更加流使用decodeImageWithImage将图片解码缓存在了内存中。这个方法对于一般的程序没有什么问题,但是如果图片是高清图片,这个方法会使得内存爆增。CGBitmapContextCreate方法官方的描述是要创建一个和像素大小相等的上下文来渲染加载这个图片,但是如果是高清大图,像素密集可能造成内存开销爆炸。SDWebimage默认的行为是解压缩缓存图片到本地,解决类似在tabelview上图片的体验问题。
根据网上给出的解决方案,最多的是对SDWebImage进行相关配置,禁止图片解压缩缓存,但是这样又会造成问题。当页面问重度使用图片的时候,没有缓存可能造成体验问题。
[[SDImageCache sharedImageCache] setShouldDecompressImages:NO];
[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];
第二种方案是先对图片进行压缩,使之需要处理的图片体积减小来达到目的,把相关方法贴出来,在SDWebImage源码UIImage+MultiFormat类中增加方法,对图片做一次等比的压缩:
-(UIImage *)compressImageWith:(UIImage *)image{
floatimageWidth = image.size.width;
floatimageHeight = image.size.height;
floatwidth =640;
floatheight = image.size.height/(image.size.width/width);
floatwidthScale = imageWidth /width;
floatheightScale = imageHeight /height;
// 创建一个bitmap的context
// 并把它设置成为当前正在使用的context
UIGraphicsBeginImageContext(CGSizeMake(width, height));
if(widthScale > heightScale) {
[imagedrawInRect:CGRectMake(0,0, imageWidth /heightScale , height)];
}
else{
[imagedrawInRect:CGRectMake(0,0, width , imageHeight /widthScale)];
}
// 从当前context中创建一个改变大小后的图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 使当前的context出堆栈
UIGraphicsEndImageContext();
}
![](https://img.haomeiwen.com/i4970273/edf1e2d39ddf3e48.png)
还有其他方法比如这位老哥
https://www.jianshu.com/p/217565ab4c33
我使用了第二种,经测设效果明显,但是还需要再优化
![](https://img.haomeiwen.com/i4970273/236a410b4799ca5b.png)
网友评论