Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circular reference between URLSessionHTTPClient and URLSession #334

Open
junpluse opened this issue Jan 9, 2025 · 2 comments · May be fixed by #335
Open

Circular reference between URLSessionHTTPClient and URLSession #334

junpluse opened this issue Jan 9, 2025 · 2 comments · May be fixed by #335
Assignees

Comments

@junpluse
Copy link

junpluse commented Jan 9, 2025

Hi,

There is a circular reference between URLSessionHTTPClient and URLSession it retains.

public init(configuration: URLSessionConfiguration = .default) {
super.init()
self.session = URLSession(
configuration: configuration,
delegate: self,
delegateQueue: .main
)
}

According to Apple documentation, URLSession's delegate object is strongly referenced.

Important
The session object keeps a strong reference to the delegate until your app exits or explicitly invalidates the session. If you do not invalidate the session by calling the invalidateAndCancel() or finishTasksAndInvalidate() method, your app leaks memory until it exits.

Since neither of the above methods are called within URLSessionHTTPClient, a memory leak occurs.

In fact, you can confirm the memory leak by launching the ElizaSwiftPackageApp included in this repository and following the steps below.

  1. Tap Connect (Unary)
  2. Tap End Chat
  3. Repeat 1-2 several times
  4. Click Debug Memory Graph in Xcode's debug area
Screenshot 2025-01-09 at 13 22 03

You can see that only one ProtocolClient remains in memory, whereas the URLSessionHTTPClient remains as many as the steps 1-2 above were repeated.

@junpluse
Copy link
Author

junpluse commented Jan 9, 2025

Although not directly related to the above, circular references seem to occur for the following stream and callbacks as well.

public func clientOnlyStream<
Input: ProtobufMessage, Output: ProtobufMessage
>(
path: String,
headers: Headers,
onResult: @escaping @Sendable (StreamResult<Output>) -> Void
) -> any ClientOnlyStreamInterface<Input> {
let clientOnly = ClientOnlyStream<Input, Output>(onResult: onResult)
let callbacks: RequestCallbacks<Input> = self.createRequestCallbacks(
path: path, headers: headers, onResult: { clientOnly.handleResultFromServer($0) }
)
return clientOnly.configureForSending(with: callbacks)
}

@rebello95
Copy link
Collaborator

Thanks for flagging this @junpluse! Should be fixed in #335.

@rebello95 rebello95 self-assigned this Jan 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants