Using @functools.cache (which is equivalent to @functools.lru_cache(maxsize=None)) on an instance method can cause unexpected memory leaks.
Because the cache stores the arguments used to call the function, and the first argument of an instance method is self, the cache retains a reference to the class instance (self) indefinitely. This prevents the Python Garbage Collector from deallocating the instance, even if it is no longer used elsewhere in your program.
To resolve this, you can:
- Use a dedicated memoization method: Store the cache on the instance itself (e.g.,
self.my_cache = functools.cache(self._uncached_func)) so the cache is released when the instance is destroyed. - Limit cache size: Use
@functools.lru_cache(maxsize=N) instead of @cache to ensure old entries are evicted. - Manual cleanup: Periodically call
.cache_clear() on the decorated function.
# Example of limiting cache size to prevent unbounded growth
@functools.lru_cache(maxsize=10000)
def factorial_plus(self, n: int) -> int:
return n * self.factorial_plus(n - 1) + self.inc if n else 1 + self.inc