#12313: Fix yet another memory leak caused by caching of coercion data
--------------------------------------------------------+-------------------
       Reporter:  SimonKing                             |         Owner:        
                                               
           Type:  defect                                |        Status:  
positive_review                                      
       Priority:  major                                 |     Milestone:  
sage-5.8                                             
      Component:  memleak                               |    Resolution:        
                                               
       Keywords:  coercion weak dictionary              |   Work issues:        
                                               
Report Upstream:  N/A                                   |     Reviewers:  Simon 
King, Jean-Pierre Flori, John Perry, Nils Bruin
        Authors:  Simon King, Jean-Pierre Flori         |     Merged in:        
                                               
   Dependencies:  #715, #11521, #12215, #13746, #13378  |      Stopgaps:        
                                               
--------------------------------------------------------+-------------------

Comment (by nbruin):

 Replying to [comment:305 SimonKing]:
 > Yep, I posted these timings as well, didn't I?
 You didn't report the timings for `ZZ` lookup with #12313  ''without''
 #13387. Probably just a pasting mistake. Doesn't matter, we have the
 general picture.

 > I am not so sure, because I think this was one of the memleaks I
 explicitly addressed somewhere.

 You did something for actions somewhere, where you ensured the maps were
 on underlying sets, for this reason. But the plain case of one ring
 coercing into another (e.g., virtually any ring into `SR`) does nail
 the ring into memory. Some examples (with #12313):

 Having no coerce map indeed works fine now:
 {{{
 sage: import gc
 sage: T=type(GF(2))
 sage:
 sage: for p in prime_range(2,300):
 ....:     k=GF(p)
 ....:     _=ZZ.has_coerce_map_from(k)
 ....:
 sage: del k
 sage: gc.collect()
 1412
 sage: len(list(o for o in gc.get_objects() if type(o) is T))
 1
 }}}
 and having coerce maps in the opposite direction doesn't hurt either:
 {{{
 sage: for p in prime_range(2,300):
 ....:     k=GF(p)
 ....:     _=k.has_coerce_map_from(ZZ)
 ....:
 sage: del k
 sage:
 sage: gc.collect()
 7852
 sage: len(list(o for o in gc.get_objects() if type(o) is T))
 1
 }}}
 But having for instance a convert map (these are cached in the same way as
 coercions) things do get nailed into memory:
 {{{
 sage: for p in prime_range(2,300):
 ....:     k=GF(p)
 ....:     _=ZZ.convert_map_from(k) #this nails k in memory
 ....:
 sage: del k
 sage: gc.collect()
 0
 sage: len(list(o for o in gc.get_objects() if type(o) is T))
 62
 }}}
 And this is why coercing into `SR` (''anything'' goes there) is so
 detrimental:
 {{{
 sage: import gc
 sage: sage: T=type(GF(2))
 sage: len(list(o for o in gc.get_objects() if type(o) is T))
 1
 sage: for p in prime_range(2,300):
 ....:     k=GF(p)
 ....:     _=SR.has_coerce_map_from(k)
 ....:
 sage: del k, _
 sage: gc.collect()
 271
 sage: len(list(o for o in gc.get_objects() if type(o) is T))
 62
 }}}
 Back to worrying things. Just to double check that element creation is not
 a problem:
 {{{
 sage: import gc
 sage: sage: T=type(GF(2))
 sage: len(list(o for o in gc.get_objects() if type(o) is T))
 1
 sage: for p in prime_range(2,300):
 ....:     k=GF(p)
 ....:     _=k(1)
 ....:
 sage: del k, _
 sage: gc.collect()
 2656
 sage: len(list(o for o in gc.get_objects() if type(o) is T))
 1
 }}}
 so one would hope that the following would be OK, but it's not. I guess
 binops get cached somewhere as well?
 {{{
 sage: for p in prime_range(2,300):
 ....:     k=GF(p)
 ....:     _=k(1)+ZZ(1)
 ....:
 sage: del k, _
 sage: gc.collect()
 0
 sage: len(list(o for o in gc.get_objects() if type(o) is T))
 62
 }}}
 (I've checked that `ZZ(1)+k(1)` gives the same result). That is a worrying
 leak, I think. Adding `ZZ(1)` to a ring element is something people are
 quite likely to think is reasonable. But that seems to nail the ring into
 memory again! I think this means there is room for a follow-up ticket. I
 think a nice lead is the result from:
 {{{
 sage: cm = sage.structure.element.get_coercion_model()
 sage: maps, actions = cm.get_cache()
 }}}
 this seems to hold plenty of references to finite fields after the last
 example, both in keys and in values (I suppose the coercion model keeps a
 lot of these things in `TripleDict`, so the key references shouldn't
 matter but the references in values do, because those would contribute to
 refcounts.

 I'm afraid the binary operation discovery of the coercion framework ''is''
 a memory leak, so the proper solution is probably to give people good
 tools to avoid depending on it.

-- 
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/12313#comment:312>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to