Skip to content

Commit 9ed4077

Browse files
authored
Fix memory leak in asyncdispatch.withTimeout by clearing losing callbacks (#25567)
withTimeout currently leaves the “losing” callback installed: - when fut finishes first, timeout callback remains until timer fires, - when timeout fires first, fut callback remains on the wrapped future. Under high-throughput use with large future payloads, this retains closures/future references longer than needed and causes large transient RSS growth. This patch clears the opposite callback immediately once outcome is decided, reducing retention without changing API behavior.
1 parent e69d672 commit 9ed4077

File tree

1 file changed

+6
-1
lines changed

1 file changed

+6
-1
lines changed

lib/pure/asyncdispatch.nim

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1946,9 +1946,14 @@ proc withTimeout*[T](fut: Future[T], timeout: int): owned(Future[bool]) =
19461946
retFuture.fail(fut.error)
19471947
else:
19481948
retFuture.complete(true)
1949+
# Timeout side lost; drop its callback to avoid retaining closures/futures.
1950+
timeoutFuture.clearCallbacks()
19491951
timeoutFuture.callback =
19501952
proc () =
1951-
if not retFuture.finished: retFuture.complete(false)
1953+
if not retFuture.finished:
1954+
retFuture.complete(false)
1955+
# Wrapped future side lost; drop its callback to avoid retaining closures/futures.
1956+
fut.clearCallbacks()
19521957
return retFuture
19531958

19541959
proc accept*(socket: AsyncFD,

0 commit comments

Comments
 (0)