On Sunday, April 6, 2014 12:23:56 PM UTC-7, Nathann Cohen wrote:
>
> > As you can see for n=6, all the 318 
> sage.graphs.linearextensions.LinearExtensions instances are still in 
> memory.  I suspect it's something like this:
> >  - The "linear_extension" method is cached. This means that the poset 
> will keep the linear_extension alive
> >  - The unique_parent of linear_extension property means that its 
> construction arguments (which includes the poset!) are used as a strong key 
> in a weak_value_dictionary. This means that as long as the linear_extension 
> is alive, the key will remain and hence the category of linear_extension 
> will keep the poset alive.
> >
> > Voila, a classic memory leak. "cached_methods" and "unique_parent" 
> combined are basically designed to invite memory leaks like this. Don't use 
> them together unless you're prepared to think very hard about basically all 
> the objects that might have a glancing interaction with the objects you're 
> implementing.
>
> Are you serious ? I'm ready to bet that a LOT of classes use those two 
> things at the same time. But there is a way to identify them automatically, 
> isn't it ?
>

If you mean by "automatic": write a script to create a lot of them and 
throw them away and see if it leaks then, yes. Otherwise: this really is a 
non-local program logic problem, so detecting it is hard.

Yep. The problem is:  UniqueRepresentation implements necessarily a GLOBAL 
cache and hence will hold strong references to the creation parameters. 
It's very unfortunate and I think if we had thought about the consequences 
of that a little more, we wouldn't have gone with this design choice at 
all. It's just too hard to work with. But now we're stuck with it.

UniqueRepresentation does try to alleviate the problems a little bit by 
using a WeakValueDictionary for its cache, but as you see: Construction 
parameter passed to a UniqueRepresentation constructor should NEVER hold a 
strong reference to the resulting object, because that creates a memory 
leak. Ideally, construction parameters should just not hold references at 
all, but that's unfortunately infeasible.

Caching a routine that's simply a wrapper around a UniqueRepresentation 
constructor is nearly useless anyway: UniqueRepresentation is supposed to 
be fast and cached anyway! (it does have to do some argument processing, 
though, so it is a little slower that a straight cached routine). However, 
I can imagine that similar scenarios occur in less obvious ways and yes, 
they all leak.

We can clean things up a little bit in this example by clearing the cache 
ourselves, i.e., run

for p in P:
    dummy=p.linear_extensions()
    p.linear_extensions.clear_cache()

but you'll find that you need to do multiple gc.collect() afterwards to get 
rid of all the crud: the garbage is so complicated that the collector can't 
clean it up in one go (the objects that get released from being 
WeakValueDictionary keys due to weakref callbacks are still part of 
reference cycles, and it takes a fresh gc run to recognize them as such)

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at http://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.

Reply via email to