Mailing List Archive

[issue44310] Document that lru_cache uses hard references
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:

Also note that many important objects in Python are not weak referenceable, tuples for example.

----------
title: lru_cache memory leak -> Document that lru_cache uses hard references

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:

I'm thinking of a more minimal and targeted edit than what is in the PR.

Per the dev guide, we usually word the docs in an affirmative and specific manner (here is what the tool does and an example of how to use it). Recounting a specific debugging case or misassumption usually isn't worthwhile unless it is a common misconception.

For strong versus weak references, we've had no previous reports even though the lru_cache() has been around for a long time. Likely, that is because the standard library uses strong references everywhere unless specifically documented to the contrary. Otherwise, we would have to add a strong reference note to everything stateful object in the language.

Another reason that it likely hasn't mattered to other users is that an lru cache automatically purges old entries. If an object is not longer used, it cycles out as new items are added to the cache. Arguably, a key feature of an LRU algorithm is that you don't have to think about the lifetime of objects.

I'll think it a for a while and will propose an alternate edit that focuses on how the cache works with methods. The essential point is that the instance is included in the cache key (which is usually what people want). Discussing weak vs strong references is likely just a distractor.

----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Pablo Galindo Salgado <pablogsal@gmail.com> added the comment:

Agreed! I will let the PR to you :)

----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:

It may useful to link back to @cached_property() for folks wanting method caching tied to the lifespan of an instance rather than actual LRU logic.

----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Serhiy Storchaka <storchaka+cpython@gmail.com> added the comment:

This is a full duplicate of issue19859. Both ideas of using weak references and changing documentation were rejected.

----------
nosy: +serhiy.storchaka
resolution: -> duplicate
superseder: -> functools.lru_cache keeps objects alive forever

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Joannah Nanjekye <nanjekyejoannah@gmail.com> added the comment:

I saw the thread but the idea was rejected by @rhettinger who seems to suggest the changes in the documentation this time himself.

Maybe he has changed his mind, in which case he can explain the circumstances of his decisions if he wants.

----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com> added the comment:

Reading this bug thread last week made me realize we had made the following error in our code:


class SomethingView():
@functools.lru_cache()
def get_object(self):
return self._object


Now, as this class was instantiated for every (particular kind of) request to a webserver and this method called (a few times), the lru_cache just kept filling up and up. We had been having a memory leak we couldn't track down, and this was it.

I think this is an easy mistake to make and it was rooted, not so much in hard references though (without that though, it would have not leaked memory) but because of the fact the cache lives on the class and not the object.

----------
nosy: +cryvate

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Change by Raymond Hettinger <raymond.hettinger@gmail.com>:


----------
pull_requests: +25303
pull_request: https://github.com/python/cpython/pull/26715

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:


New changeset fafcfff9262ae9dee03a00006638dfcbcfc23a7b by Raymond Hettinger in branch 'main':
bpo-44310: Note that lru_cache keep references to both arguments and results (GH-26715)
https://github.com/python/cpython/commit/fafcfff9262ae9dee03a00006638dfcbcfc23a7b


----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Change by miss-islington <mariatta.wijaya+miss-islington@gmail.com>:


----------
nosy: +miss-islington
nosy_count: 8.0 -> 9.0
pull_requests: +25304
pull_request: https://github.com/python/cpython/pull/26716

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Change by Raymond Hettinger <raymond.hettinger@gmail.com>:


----------
resolution: duplicate -> fixed
stage: patch review -> resolved
status: open -> closed

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:


New changeset 809c3faa032d32bc45a0fa54d0400fcbc42a618f by Miss Islington (bot) in branch '3.10':
bpo-44310: Note that lru_cache keep references to both arguments and results (GH-26715) (GH-26716)
https://github.com/python/cpython/commit/809c3faa032d32bc45a0fa54d0400fcbc42a618f


----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Change by Raymond Hettinger <raymond.hettinger@gmail.com>:


----------
pull_requests: +25319
pull_request: https://github.com/python/cpython/pull/26731

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:

See PR 26731 for a draft FAQ entry. Let me know what you think.

----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com> added the comment:

PR 26731 looks very good to me. My only comment, which I am not sure is worthy of adding/is a general lru_cache thing, that "instances
are kept alive until they age out of the cache or until the cache is
cleared", if you are creating instances and calling this method all the time, will lead to an infinite memory leak.

Not sure whether that's too specific to the problem we encountered and we are all consenting adults and should infer this or it is helpful: leave it up to your/other people's judgement.

P.S. In the programming.rst there is also the "Why are default values shared between objects?" section which actually uses default values to make its own poor version of a cache. It should probably at least mention lru_cache could be used (unless you particularly need callers to be able to pass their own cache).

----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:

> if you are creating instances and calling this method
> all the time, will lead to an infinite memory leak.

Your words aren't making any sense to me. The default
lru_cache will never hold more than maxsize entries.
The default maxsize is 128. How is that "infinite"?

----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com> added the comment:

I clearly was missing some words there Raymond. I meant, if one has set maxsize=None.

----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com> added the comment:

(but consenting adults, setting max_size=None for "efficiency", you better be sure what you are doing in a long running process and making sure it cannot grow unbounded.)

----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:

> I meant, if one has set maxsize=None.

The docs already say, "If maxsize is set to None, the LRU feature is disabled and the cache can grow without bound."

----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Change by miss-islington <mariatta.wijaya+miss-islington@gmail.com>:


----------
pull_requests: +25363
pull_request: https://github.com/python/cpython/pull/26777

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:


New changeset 7f01f77f8fabcfd7ddb5d99f12d6fc99af9af384 by Raymond Hettinger in branch 'main':
bpo-44310: Add a FAQ entry for caching method calls (GH-26731)
https://github.com/python/cpython/commit/7f01f77f8fabcfd7ddb5d99f12d6fc99af9af384


----------
message_count: 18.0 -> 19.0
pull_requests: +25363
pull_request: https://github.com/python/cpython/pull/26777

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Change by miss-islington <mariatta.wijaya+miss-islington@gmail.com>:


----------
pull_requests: +25364
pull_request: https://github.com/python/cpython/pull/26778

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:


New changeset 77eaf14d278882857e658f83681e5b9a52cf14ac by Miss Islington (bot) in branch '3.10':
bpo-44310: Add a FAQ entry for caching method calls (GH-26731) (GH-26777)
https://github.com/python/cpython/commit/77eaf14d278882857e658f83681e5b9a52cf14ac


----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Change by Raymond Hettinger <raymond.hettinger@gmail.com>:


----------
pull_requests: +25373
pull_request: https://github.com/python/cpython/pull/26789

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com
[issue44310] Document that lru_cache uses hard references [ In reply to ]
Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:

Adding a weak referencing recipe here just so I can find it in the future.

--------------------------------------------------------------------------

import functools
import weakref

def weak_lru(maxsize=128, typed=False):
"""LRU Cache decorator that keeps a weak reference to "self".

Only provides benefit if the instances are so large that
it is impractical to wait for them to age out of the cache.

When the instance is freed, the cache entry still remains
but will be unreachable.

If new instances will be created that are equal to the ones
retired by the weak reference, we lose all the benefits of
having cached the previous call.

If the class defines __slots__, be sure to add '__weakref__'
to make the instances weak referenceable.

"""

def decorator(func):

ref = weakref.ref

@functools.lru_cache(maxsize, typed)
def _func(_self, /, *args, **kwargs):
return func(_self(), *args, **kwargs)

@functools.wraps(func)
def wrapper(self, /, *args, **kwargs):
return _func(ref(self), *args, **kwargs)

return wrapper

return decorator

----------

_______________________________________
Python tracker <report@bugs.python.org>
<https://bugs.python.org/issue44310>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com