从一个AFNetworking循环引用说起

简介: 本文分析使用代码是AFNetworking 3.2.1最近使用Instruments中的Leaks分析项目内存泄露,发现了一个AFNetworking的循环引用。

本文分析使用代码是AFNetworking 3.2.1

最近使用Instruments中的Leaks分析项目内存泄露,发现了一个AFNetworking的循环引用。如下图所示:

img_d87589dbb97ad7ef55d400d164597e7f.jpe
15354171666142.jpg

通过调用栈发现产生泄露的代码在这里:

// AFURLSessionManager.m
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    // ... 初始化代码,省略

    // 导致循环引用的方法
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

    // ... 其它初始化代码,省略
    return self;
}

大致原因就是AFURLSessionManager引用NSURLSession,同时设置NSURLSession的delegate为自己,NSURLSession会强引用delegate,于是产生了循环引用。

关于NSURLSession的delegate官方说明:
This delegate object is responsible for handling authentication challenges, for making caching decisions, and for handling other session-related events. The session object keeps a strong reference to this delegate until your app exits or explicitly invalidates the session. If you do not invalidate the session, your app leaks memory until it exits.

解决方案

在AFNetworking官方issues找到了相关的问题Possible memory leak in AFURLSessionManager。作者的回答如下:

img_0732f7735e1a9c2531bc6f4800488303.jpe
15353328585634.jpg

解决方案有两种:

  1. 这是最常见也是作者推荐的方法,只创建一个AFURLSessionManager,整个APP共享,虽然还是有循环引用,但是就没有内存泄露的问题了。
  2. 如果要使用多个AFURLSessionManager,在使用完成后手动调用invalidateSessionCancelingTasks:来断开循环引用。(这种方案不推荐,具体原因看下一小节)

AFURLSessionManager复用

关于AFURLSessionManager是否使用单例这个问题,官方demo使用的是单例,在苹果官方文档找到这么一段话

With the NSURLSession API, your app creates one or more sessions, each of which coordinates a group of related data transfer tasks. For example, if you’re creating a web browser, your app might create one session per tab or window, or one session for interactive use and another for background downloads. Within each session, your app adds a series of tasks, each of which represents a request for a specific URL (following HTTP redirects, if necessary).

我的理解是这样的,根据使用场景的不同,这个问题有不同的答案,在大多数场景下APP都是在和同一服务器打交道,一个session就够了,如果有连接多个服务器、或者后台下载等功能需求,可以给每个服务器、后台下载任务创建单独的session(但是也不能每个请求都单独创建session)。

在查找资料的时候,我发现有博客提到单例seesion可以减少TCP三次握手,动手验证下:

多个网络请求复用一个AFURLSessionManager,连续发两个网络请求,用Wireshark抓包可以看到,第二次网络请求复用了第一次的TCP连接,没有做三次握手。

img_2a35c0f5d09e53b81f436f7b80714c7d.jpe
15354191775340.jpg

下图是每次网络请求都新建一个AFURLSessionManager的抓包,可以看到每个网络请求都进行了TCP三次握手。

img_3b3b81c94702561a587e1ef98d61ce45.jpe
15354193039698.jpg

实验结果的确如网上所说,复用AFURLSessionManager可以减少三次握手,提升效率。

博客链接

目录
相关文章
|
6月前
|
前端开发 JavaScript 程序员
一文搞懂:关于Defferred对象知识详解
一文搞懂:关于Defferred对象知识详解
79 0
|
Java C++ Ruby
对 Ruby 中内存泄漏的“浅”探究
对 Ruby 中内存泄漏的“浅”探究
224 0
|
iOS开发
iOS开发 - 打包静态framework后,引用时必须做的一件事,否则崩溃
iOS开发 - 打包静态framework后,引用时必须做的一件事,否则崩溃
195 0
|
C语言 iOS开发
OC 底层知识(二): KVO
OC 底层知识(二): KVO
190 0
OC 底层知识(二): KVO
|
iOS开发
afnetworking 内存泄漏问题
afnetworking 内存泄漏问题
372 0
afnetworking 内存泄漏问题
|
安全 Unix 程序员
OC底层知识(十一) : 多线程
OC底层知识(十一) : 多线程
205 0
OC底层知识(十一) : 多线程
|
编译器 iOS开发
iOS-底层原理 23:KVO 底层原理
iOS-底层原理 23:KVO 底层原理
214 0
iOS-底层原理 23:KVO 底层原理
|
API
OC底层知识(三): KVC
OC底层知识(三): KVC
187 0
OC底层知识(三): KVC
|
设计模式 图形学
同事看了我的代码惊呼:居然是这么在Unity中用单例的
今天,同事问我:“在Unity中怎么用单例呀” 然后我就把我写的代码甩过去了。 同事:“哦,原来是这么用的,你来给我演示一下吧”
|
存储 消息中间件 JavaScript
一文搞懂jsBridge的运行机制
一文搞懂jsBridge的运行机制
444 0