本文分析使用代碼是 AFNetworking 3.2.1
最近使用
Instruments
中的
Leaks
分析項目記憶體洩露,發現了一個AFNetworking的循環引用。如下圖所示:

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。作者的回答如下:
15353328585634.jpg
解決方案有兩種:
- 這是最常見也是作者推薦的方法,隻建立一個AFURLSessionManager,整個APP共享,雖然還是有循環引用,但是就沒有記憶體洩露的問題了。
- 如果要使用多個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連接配接,沒有做三次握手。
15354191775340.jpg
下圖是每次網絡請求都建立一個
AFURLSessionManager
的抓包,可以看到每個網絡請求都進行了TCP三向交握。
15354193039698.jpg
實驗結果的确如網上所說,複用
AFURLSessionManager
可以減少三次握手,提升效率。
部落格連結