Skip to content

v1.8.52

Choose a tag to compare

@MrRobotoGit MrRobotoGit released this 01 Jul 10:28

fix: wire up dead CloseHash() call, fixing critical piece-buffer memory leak
Storage.CloseHash() removes a torrent's *Cache (and all its MemPiece piece
buffers received from peers) from the global Storage.caches map. It was
defined but never called anywhere in the codebase - Torrent.Close() only
removed the torrent from bt.torrents and dropped the underlying anacrolix
torrent, leaving its Cache permanently referenced in Storage.caches for the
rest of the process lifetime.

Every torrent ever touched (movie/TV sync, watchlist, Plex library scans)
accumulated its piece buffers in RAM forever, even after expiring via the
normal 45s-timeout torrent reaper. Heap profile taken during a combined
Plex-scan + movie-sync + TV-sync stress test showed 6.1GB (89% of the heap)
reachable via torrstor.(*MemPiece).WriteAt, all attributed to peer connection
read loops (Peer.receiveChunk -> PeerConn.mainReadLoop) - consistent with
buffers from every torrent activated since process start never being freed.
System swap was at 5.0/5.1GB used (near exhaustion) when captured.

Now calls storage.CloseHash(hash) in Torrent.Close(), covering both the
expiry path (UpdateStats -> RemoveTorrent) and explicit removal
(DropTorrent API). Cache.Close() is idempotent (guarded by isClosed), so
this is safe even if anacrolix's storage.TorrentImpl.Close callback also
fires for the same hash.

Full Changelog: v1.8.51...v1.8.52