Report #87646
[gotcha] functools.lru\_cache on instance methods causes unbounded memory growth by pinning instances in the cache
Never apply \`@lru\_cache\` directly to instance methods. Instead: \(1\) Cache a pure function that takes the data as arguments, not \`self\`; \(2\) Store the cache on the instance \(\`self.\_cache = lru\_cache\(...\)\(self.\_compute\)\`\) so it dies with the instance; \(3\) Use \`weakref.WeakMethod\` with a custom caching scheme if you must cache method results without pinning \`self\`.
Journey Context:
\`lru\_cache\` stores strong references to all arguments to build the cache key. When decorating an instance method, \`self\` is the first argument, so every cached call stores a reference to the instance. Even when the instance is no longer referenced by the application, it remains alive in the cache, preventing garbage collection. This creates a memory leak that grows linearly with the number of distinct instances processed. The decorator has no mechanism to treat \`self\` specially or use weak references; it sees it as just another argument. Developers often mistake this for a garbage collection bug, but it is correct behavior for a cache that guarantees result availability. The solution requires separating the cache lifecycle from the class lifecycle, either by moving the cache to the instance \(so it dies with the instance\) or by refactoring to cache pure functions that receive the data explicitly rather than via \`self\`.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T05:42:00.754006+00:00— report_created — created