性能优化-内存泄漏

1 Analyze

Product-Analyze
请添加图片描述

1.Dead store:无效数据

  • 未被读取
  • 在其初始化期间永远不会被读取
Value stored to 'finalStr' is never read
Value stored to 'url' during its initialization is never read

2.Memory error:内存错误

  • 从预期返回非空值的方法返回的 nil
return nil; 
//nil returned from a method that is expected to return a non-null value

3.Logic error:逻辑错误

  • 被调用的函数指针为空(空解引用)
gifdoneHandle(nil); 
//Called function pointer is null (null dereference)

4.Core Foundation/Objective-C:框架或者是OC语法错误

  • 直接返回 ‘self’ ,而没有设置为 ‘[(super or self) init…]’
return self; 
//Returning 'self' while it is not set to the result of '[(super or self) init...]'

5.Memory(Core Foundation/Objective-C/OSObject):内存

  • 调用者此时不拥有的对象的引用计数不正确递减
        CGImageRelease(imageRef) 导致的过度释放内存。因为imageRef属于CGImageRef,CGImageRef属于CGImage,所以imageRef的释放应该是在CGImage的Controller中。

那么CGImage到底是啥呢?
    CGImage是一个C结构,也就是将其作为参数或返回值传递时都将复制它。
    据源码可知,CGImageRef是一个指针类型。

typedef struct CF_BRIDGED_TYPE(id) CGImage *CGImageRef;

        下面两种写法的区别是第一个imageRef是由image转为imageRef,第二个是由imageRef转为image
第一种:由image转为imageRef

CGImageRef imageRef = [UIImage imageNamed:@"AppIcon"].CGImage;
[zoomingScrollView setShowImage:[UIImage imageWithCGImage:imageRef]];
CGImageRelease(imageRef); //过度释放
//Incorrect decrement of the reference count of an object that is not owned at this point by the caller

第二种:由imageRef转为image
        此时不会造成内存被过度释放,imageRefRect是在这里creat,自然要在这里面对其进行释放,而C类对象没有ARC,所以需要手动释放内存。此时的CGImageRelease合情合理。

CGImageRef imageRefRect = CGImageCreateWithImageInRect([fixedImage CGImage], rect);
UIImage* subImage = [UIImage imageWithCGImage: imageRefRect];
CGImageRelease(imageRefRect);//可以释放,也可以不释放

针对于CGImageCreateWithImageInRect里面的方法解释如下,可以看到“ 生成的图像保留对原始图像的引用,因此您可以调用此函数后释放原始图像。”
也就是说调用这个方法后,也就是将image引用,可以在当前方法中对其进行释放。


/* Create an image using the data contained within the subrectangle `rect'
   of `image'.
   The resulting image retains a reference to the original image, so you may
   release the original image after calling this function. */

翻译的结果是:
使用包含在子矩形“rect”中的数据创建图像 ‘image’。
生成的图像保留对原始图像的引用,因此您可以调用此函数后释放原始图像。

2 Instruments-Leaks

请添加图片描述

  • Xcode-Preferences-Instruments
  • 进入之后选择Leaks
  • 运行程序
  • 选择设备和应用程序
  • 点击红圈圈⭕️开始运行吧~
  • 红色❎出现双击点进去,选择Call Tree,双击代码行或者是Reveal in Xcode即可进入代码行查看
    请添加图片描述

AFN导致的内存泄漏

1、AFHTTPSessionManager导致的内存泄漏
AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];//内存泄漏定位的代码

可以看到manager的方法其实是一个类方法,这就导致每一次请求都会去访问,导致内存泄漏。

+ (instancetype)manager {
    return [[[self class] alloc] initWithBaseURL:nil];
}

可以将其改为一个单例

+(AFHTTPSessionManager *)AFNManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [AFHTTPSessionManager manager];         
        manager.requestSerializer.timeoutInterval = 10.f;
    });
    return manager;
}

此时再调用就不会产生内存泄漏了

AFHTTPSessionManager *mgr = [self AFNManager];
2、NSURLSession导致的强引用delegate

在这里插入图片描述

self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];//泄漏代码位置

三个参数:

@property (readwrite, nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration;
@property (nullable, readonly, retain) id <NSURLSessionDelegate> delegate;
// 运行委托回调的操作队列。
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;

可以看到delegate是强引用,源码中解释如下:

 * Customization of NSURLSession occurs during creation of a new session.
 * If you only need to use the convenience routines with custom
 * configuration options it is not necessary to specify a delegate.
 * If you do specify a delegate, the delegate will be retained until after
 * the delegate has been sent the URLSession:didBecomeInvalidWithError: message.

翻译:

* NSURLSession 的自定义发生在创建新会话期间。
* 如果您只需要使用自定义的便利例程
* 配置选项 没有必要指定一个delegate。
* 如果你指定了一个delegate,delegate将被保留到之后
* 委托已发送 URLSession:didBecomeInvalidWithError: 消息。

也就是说在这种情况下,使用NSURLSession实例化一个session之后,只要session存在,则delegate存在。
解决方法就是如果不用session之后,就将其释放。

3、AFSecurityPolicy导致的内存泄漏(后续补充)
AFSecurityPolicy *securityPolicy = [[self alloc] init];

源码解释AFSecurityPolicy:

/**
 `AFSecurityPolicy` evaluates server trust against pinned X.509 certificates and public keys over secure connections.

 Adding pinned SSL certificates to your app helps prevent man-in-the-middle attacks and other vulnerabilities. Applications dealing with sensitive customer data or financial information are strongly encouraged to route all communication over an HTTPS connection with SSL pinning configured and enabled.
 */

翻译:
AFSecurityPolicy根据固定的 X.509 证书和安全连接上的公钥评估服务器信任。
将固定 SSL 证书添加到您的应用程序有助于防止中间人攻击和其他漏洞。强烈建议处理敏感客户数据或财务信息的应用程序通过配置和启用 SSL 固定的 HTTPS 连接路由所有通信。
源码解释NSCode

// Objects which are safe to be encoded and decoded across privilege boundaries should adopt NSSecureCoding instead of NSCoding. Secure coders (those that respond YES to requiresSecureCoding) will only encode objects that adopt the NSSecureCoding protocol.
// NOTE: NSSecureCoding guarantees only that an archive contains the classes it claims. It makes no guarantees about the suitability for consumption by the receiver of the decoded content of the archive. Archived objects which  may trigger code evaluation should be validated independently by the consumer of the objects to verify that no malicious code is executed (i.e. by checking key paths, selectors etc. specified in the archive).

翻译:
// 可以安全地跨权限编码和解码的对象应该采用 NSSecureCoding 而不是 NSCoding。安全编码器(对 requiresSecureCoding 响应 YES 的那些)只会编码采用 NSSecureCoding 协议的对象。
// 注意:NSSecureCoding 仅保证存档包含它声明的类。它不保证存档的解码内容的接收者是否适合使用。可能触发代码评估的存档对象应由对象的使用者独立验证,以验证没有执行恶意代码(即通过检查存档中指定的关键路径、选择器等)。

4、 基于AFN进行二次封装的组件库AFJSONResponseSerializer初始化导致的内存泄漏

请添加图片描述
如5.

5、[AFHTTPResponseSerializer init]泄漏
AFJSONResponseSerializer *serializer = [[self alloc] init];

归根结底还是AFHTTPSessionManager的问题
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Αиcíеиτеǎг

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值