美文网首页
2019-08-04

2019-08-04

作者: taozhou | 来源:发表于2019-08-18 15:03 被阅读0次

前言

因为公司APP会在Ipad mini(运行内存为512M)上会崩溃,在其他设备上能正常运行,在instrument上调试发现在崩溃页面占用内存暴涨,导致程序崩溃。调试发现主要原因是合成大尺寸图片时,合成图片的位图未被及时释放,VM CGRaster data中存在多张合成大图的位图,导致程序崩溃。

Instruments中的Allocations

Allocations工具用于检查程序的内存分配。其中Allocation主要分为All Heap及All Anonymous VM 两部分。All Heap代表程序真实占用的内存,而All Anonymous Vm代表系统为程序分配的虚拟内存。VM由以下三部分组成:

  1. VM:ImageIO_PNG_Data 主要用于系统缓存图片
  2. VM:CG raster data 主要用于缓存光栅化图片。如位图
  3. VM:CoreAnimation 主要用于核心动画的缓存。

点我查看Allocations参考资料

VM:CG raster data导致内存暴涨问题

加载5120*2880像素的大图

//测试cg raster data
- (void)__rasterDataImage {
    NSString *pic3Path = [NSBundle.mainBundle pathForResource:@"pic3" ofType:@"jpg"];
    UIImage *pic3 = [UIImage imageWithContentsOfFile:pic3Path];
    UIImageView *imageView1 = [[UIImageView alloc] initWithImage:pic3];

    
    UIGraphicsBeginImageContextWithOptions(pic3.size, YES, 1);
    [imageView1.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *pic1Img = UIGraphicsGetImageFromCurrentImageContext();
//    CGContextClearRect(UIGraphicsGetCurrentContext(), imageView1.frame);
    UIGraphicsEndImageContext();
    

    UIImage *img =  [UIImage imageWithData:UIImagePNGRepresentation(pic1Img)] ;
    UIImageView *imageView = [[UIImageView alloc] initWithImage:img];
    
    [self.view addSubview:imageView];
}

测试结果


获取位图图片之后转为NSData在显示.png
注释UIImage *img =  [UIImage imageWithData:UIImagePNGRepresentation(pic1Img)] ;
将
UIImageView *imageView = [[UIImageView alloc] initWithImage:img];
替换为
UIImageView *imageView = [[UIImageView alloc] initWithImage:picImg];

测试结果如下


直接显示位图.png

结果分析

第一幅结果图中的VM:ImageIO_PNG_Data用于需要显示的大图位图数据。(采用imageWithContentsOfFile系统不会一直缓存,当无指针引用该大图时,该ImageIO_PNG_Data中的此位图会自动释放。而采用imageNamed系统会缓存该大图)
第二幅测试结果图中的VM:CG raster data大小为56.25MB = 5120 * 2880 * 4B / (1024 * 1024)。说明raster data中存放的是大图的位图。

结论

当合成图片时若该图不需理解显示,不应该直接返回该UIImage对象,若外部引用该UIImage对象会导致该位图一直不会被释放,占用大量内存。而应对其做处理将其转换NSData在生成新的UIImage对象返回回去

补充

VM:ImageIO_PNG_Data中的位图创建时机

//测试代码
- (void)__loadBigPngImage {
    NSString *pic1Path = [NSBundle.mainBundle pathForResource:@"pic4" ofType:@"png"];
    UIImage *pic1 = [UIImage imageWithContentsOfFile:pic1Path];
    UIImageView *imageView1 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, pic1.size.width, pic1.size.height)];
    imageView1.image = pic1;
    self.imgView = imageView1;
    //self.view insertSubview:imageView1 atIndex:0];
}

测试结果


Image_PNG_Data测试 不显示到界面.png
取消self.view insertSubview:imageView1 atIndex:0];的注释

测试结果


Image_PNG_Data测试 显示到界面.png

结论
从上测试效果可得,如果图片是PNG图片,那么Image_PNG_Data分配内存给位图是在图片需显示在界面上。

存在的疑问

  1. iphone/ipad设备的虚拟内存功能是否开启,假如虚拟内存功能开启,内存超过512M程序应该也不会崩溃。但是如果没有开启虚拟内存为什么All anonymous VM 分配了内存的。(猜测All anonymous VM应该是分配到RAM上的,才会导致崩溃。我仅找到了如何通过越狱开启iphone/ipad虚拟内存功能,求大佬解释)

相关文章

网友评论

      本文标题:2019-08-04

      本文链接:https://www.haomeiwen.com/subject/yolydctx.html