从一个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可以减少三次握手,提升效率。

博客链接

目录
相关文章
|
2月前
|
数据采集 Python
再谈re的应用
再谈re的应用
36 2
|
6月前
|
设计模式 Swift iOS开发
【Swift开发专栏】Swift中的协议与委托模式
【4月更文挑战第30天】Swift编程语言强调协议与委托模式。协议定义了类型需实现的方法和属性,如`SomeProtocol`示例。遵循协议的类、结构体或枚举需实现协议要求。协议可继承,也可作为类型使用。委托模式让对象间通信更灵活,通过协议实现,如`DataSourceDelegate`示例。实战案例展示了在`UITableView`和自定义下载器中使用委托模式。
122 0
|
5月前
|
前端开发 JavaScript 程序员
一文搞懂:关于Defferred对象知识详解
一文搞懂:关于Defferred对象知识详解
75 0
|
存储 安全 Java
C++第十一节——单例模式 C++11 智能指针 异常 有关讲述
可以用同样的方式来实现,就是将构造函数私有化,然后让创建类的时候只能通过一个接口函数来实现,而在这个接口函数中我们将其创建在栈上。
423 3
C++第十一节——单例模式 C++11 智能指针 异常 有关讲述
|
iOS开发
iOS开发 - 打包静态framework后,引用时必须做的一件事,否则崩溃
iOS开发 - 打包静态framework后,引用时必须做的一件事,否则崩溃
191 0
|
C语言 iOS开发
OC 底层知识(二): KVO
OC 底层知识(二): KVO
189 0
OC 底层知识(二): KVO
|
IDE 测试技术 API
聊聊我的源码阅读方法
本次代码阅读的项目来自 500lines 的子项目 web-server。 500 Lines or Less不仅是一个项目,也是一本同名书,有源码,也有文字介绍。这个项目由多个独立的章节组成,每个章节由领域大牛试图用 500 行或者更少(500 or less)的代码,让读者了解一个功能或需求的简单实现。
161 0
聊聊我的源码阅读方法
|
API
OC底层知识(三): KVC
OC底层知识(三): KVC
185 0
OC底层知识(三): KVC
|
iOS开发
afnetworking 内存泄漏问题
afnetworking 内存泄漏问题
368 0
afnetworking 内存泄漏问题
|
设计模式 图形学
同事看了我的代码惊呼:居然是这么在Unity中用单例的
今天,同事问我:“在Unity中怎么用单例呀” 然后我就把我写的代码甩过去了。 同事:“哦,原来是这么用的,你来给我演示一下吧”