美文网首页
iOS 内存监控与治理(四)- foom问题治理与优化

iOS 内存监控与治理(四)- foom问题治理与优化

作者: topws1 | 来源:发表于2021-10-22 20:22 被阅读0次

本章节列举对内存使用不合理的场景及优化方案,在实际的研发中还是需要同学们严格遵守代码规范,避免踩坑。

共有以下几点:
1、使用NSCache
2、避免内存泄漏
3、移除当前未使用的内存
4、优化图片使用

使用缓存

使用 NSCache不仅能保证线程安全,同时在收到内存警告时,可以释放未使用的内存,此外针对compressed memory,NSCache 也有优化。
在实际的研发中,也推荐对缓存设置上限,比如YY 中关于图片缓存设置一个最大的缓存值。对于缓存设置上限后引入的缓存清除策略,也可以参考YY 使用 LRU(last recently use)方式,更新缓存值。

避免内存泄漏

内存泄漏是指申请的内存空间使用完毕之后未回收。造成内存泄漏的原因有很多,各个场景也不尽相同,下面列举常见一些场景。

Block 使用不当等原因造成的循环引用
  • self 持有的Block 内直接使用了self,这种属于非常常见的循环引用了,不过这里还是不推荐大家遇到Block无脑使用weakSelf,使用 weakSelf是会造成额外的性能损耗的,像常见的使用GCD Block内是不需要使用弱引用的
  • 隐含的循环引用,比如superView -> self.xxxView -> self.xxxView.block -> superView。有一些场景并不会直接使用self关键字,但是由于addSubview等方式会持有一些子View,这些子View 又可能持有其他子View且这些子View 可能会使用Block,这时候就需要特别注意,最好理清所有对象的引用关系,避免循环引用。
子线程runloop没有停掉,导致子线程一直存活。

一般来说子线程在任务结束后 会自动关闭,但是如果子线程中由于定时器功能,会打开runloop,如果不先停止runloop的话,子线程也就无法正常关闭

移除未使用的内存

  • 消息列表中已不可见的消息数据
  • 进入后台后,当前页面可以移除

优化图片使用

图片所占用的内存对于大多数APP 来说都是不能忽视的,合理的使用图片不仅需要研发尽量保证编码规范,还需要实施一些图片大小监控。

1、避免将图片放在内存里
  • 解码后的UIImage 占用的内存比较大,如果当前不需要显示时,可以不放在内存里
  • 同一个页面使用重复资源时,避免重复创建(比如 解码的YYImage)
  • 批量使用图片的场景,推荐使用autoreleasepool等方式及时释放内存
  • 大图不放在Asset中且通过 imageWithContentOfFile读取
2、图片裁剪

大多情况下业务场景需要显示的图片尺寸小于图片的原始尺寸。图片裁剪一般有两种选择,一是在后端下发图片的时候,不同场景下发不同尺寸的URL;二是图片下载后,客户端对原图进行合适的裁剪。

3、图片绘制及缩放使用 UIGraphicsImageRenderer 和 ImageIO

常见的UIGraphicsBeginImageContextWithOptions绘图方式会有两个问题:
(1)默认是 SRGB 的格式,也就是说每个像素需要占 4 个 bytes 的空间,对于一些黑白或者仅有 alpha 通道的数据来说是没有必要的。
(2)需要将原图片完全解码后渲染出来,原图片的解码会造成内存占用的高峰。

iOS 12之后,使用UIGraphicsImageRenderer绘图。系统会自动选择合适的颜色格式,避免不必要的内存消耗。
对于原方法需要解码原图造成内存暴涨的问题,可以考虑用ImageIO来解决。ImageIO可以直接读取图像大小和元数据信息,不会带来额外的内存开销。

这里附上ImageIO 创建缩略图的使用代码

+ (UIImage *)getThumbImageWithMax:(CGFloat)max imageData:(NSData *)imageData {
    if (imageData.length == 0) {
        return nil;
    }
    CFDictionaryRef dicOptionsRef = (__bridge CFDictionaryRef) @{(id)kCGImageSourceCreateThumbnailFromImageAlways : @(YES),
                                                                 (id)kCGImageSourceThumbnailMaxPixelSize : @(max),
                                                                 (id)kCGImageSourceShouldCache : @(NO),
                                                                 (id)kCGImageSourceCreateThumbnailWithTransform:@(YES)
    };
    
    CGImageSourceRef src = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, nil);
    CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(src, 0, dicOptionsRef);
    UIImage *newImage = [UIImage imageWithCGImage:imageRef];
    if (imageRef != nil) CFRelease(imageRef);
    CFRelease(src);
    return newImage;
}

相关文章

网友评论

      本文标题:iOS 内存监控与治理(四)- foom问题治理与优化

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