URLSessionWebSocketTask调用invalidate后未释放的问题排查
iOS 15.7下WebSocket Session及Task内存泄漏排查方案
未主动取消WebSocket Task
调用cleanup时必须显式调用WebSocketTask的cancel(with:reason:)方法,不能仅依赖Session的失效操作。iOS 15.x版本中,若WebSocketTask未被主动取消,即使Session失效,底层CFNetwork仍可能持有该Task的引用。示例代码:func cleanup() { webSocketTask?.cancel(with: .normalClosure, reason: nil) webSocketTask = nil // 后续处理Session }URLSession与Delegate的循环引用
URLSession会强持有其delegate对象,直到Session被显式失效。若你的SocketService类强引用Session,同时作为Session的delegate,就会形成循环引用,导致实例无法被正确释放。解决方法是在cleanup中先调用Session的invalidateAndCancel(),再将Session引用置空:func cleanup() { // 先取消Task webSocketTask?.cancel(with: .normalClosure, reason: nil) webSocketTask = nil // 失效并置空Session session?.invalidateAndCancel() session = nil }- 在Delegate方法的闭包中,需用
[weak self]捕获self,避免闭包强引用导致的循环泄漏:func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didReceive message: URLSessionWebSocketTask.Message) { DispatchQueue.main.async { [weak self] in self?.handleReceivedMessage(message) } }
未等待Session异步失效完成
invalidateAndCancel()是异步操作,调用后需等待Delegate收到urlSession(_:didBecomeInvalidWithError:)回调,再完成资源释放。若提前置空相关引用,底层CFNetwork可能未完成清理,导致Task残留。可通过回调等待Session失效:private var cleanupCompletion: (() -> Void)? func cleanup(completion: @escaping () -> Void) { webSocketTask?.cancel(with: .normalClosure, reason: nil) webSocketTask = nil session?.invalidateAndCancel() cleanupCompletion = completion } func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) { session = nil cleanupCompletion?() cleanupCompletion = nil }iOS 15.7系统固有Bug
iOS 15.x系列的CFNetwork模块在WebSocketTask的资源回收上存在已知泄漏问题,尤其在频繁创建销毁连接时表现明显。可尝试升级至iOS 16+版本验证,若泄漏消失则为系统Bug。临时 workaround 可限制连接创建频率,或在cleanup后延迟1-2秒再释放相关引用(仅作临时方案,不推荐长期使用)。
内容的提问来源于stack exchange,提问作者rony_y
相关产品推荐
相关产品推荐

