Re: Closure shadowing

On Fri, 2005-04-29 at 15:16 +0100, Gustavo J. A. M. Carneiro wrote:

> > We have a reference cycle that goes through both python and GObject,
> > and is thus uncollectable. If we were dealing with a widget the
> > signal would be removed at gtk_widget_destroy() time, but that doesn't
> > help us for a GObject like GtkAction.
> > 
> > The technique that Python uses to fix this cycle is something I'll
> > call "closure shadowing".
>   "Python uses"?  You are proposing, or are you saying things are like
> this already?  

I'm saying things are like this already. But I made some simplifications
for people who aren't familiar with Python's exotic (though neat)
garbage collection scheme.

> I don't think they are.  pygtk's solution is more like
> this (jamesh please correct me if I'm wrong):
>  +-----------+       +------------------+      +------------------+
>  | ActioInfo |  ---> |  PyRadioAction   | ---> |  GtkRadioAction  | 
>  | (Python   |       |   (PyGObject)    |      |     (GObject)    |
>  |  Object)  |       |                  |      |                  |
>  +-----------+       +------------------+      +------------------+
>       ^                               |                 |
>       |                               v                 v
>  +-------------+                  +-------------------------+
>  | OnActivate  | <--------------- |        PyGClosure       |
>  | Python      |                  |     (is-a GClosure)     |
>  | callback    |                  |                         |
>  +-------------+                  +-------------------------+
>   Python's GC, when looking for cycles to collect, asks (tp_traverse
> slot) the PyGObject (PyRadioAction) for all python object references
> that it contains.  Then it looks a a list of closures being tracked, and
> answers with a list of python objects contained in the tracked closures.
> Thus, the GC discovers the cycle PyRadioAction -> OnActivate ->
> ActionInfo -> (back to) PyRadioAction, and frees it (but only when
> GtkRadioAction refcount == 1).

You can think of the PyGClosure as a combination of a Python object
(it participates in Python's garbage collection scheme) and a GClosure.
The fact that you use a single memory block isn't really relevant
to explaining the concept.


>   I think it is already collectable, thus this solution, for the python
> case, adds complexity with not much gain...

I wasn't suggesting any changes to PyGTK ... my mail was explaining
the PyGTK to other people. (In a somewhat modified form, because few
other languages have a GC much like Python)

>   ...although it would be nice to not rely on cyclic GC; it already
> causes transient memory problems, that appear like leaks to newbies,
> with GObjects holding large chunks of memory, such as pixbufs.
>   One more thing; in pygtk, we need the python wrapper to never be
> collected as long as the corresponding GObject is alive.  This is
> because the GObject python wrappers has a dictionary for the programmer
> to add attributes freely.  Programmers expect this dictionary to be kept
> unchanged even when python-land loses track of the GObject.

You also need it to stay alive for the closure scheme to work. (Or
use a two-part wrapper object scheme like Alex suggests in: )

>   For instance, say you create a GObject in python, add some attributes
> to it, then store it in a tree model.  With what you propose, at this
> point the python gobject wrapper would be collected (thus destroyed).

No, I was talking only about closure memory handling. It doesn't address
the lifecycle issue for the proxy/GObject pair. 

I think the Python scheme for that is fine, though, as you point out,
the fact that it gets triggered for all GObjects, even when there is
no signals or setting of data in the instance dictionary means things
get collected rather slowly.

For languages that have a less customizable garbage collector than
Python, I recently proposed adding a "toggle references" feature to
The big restriction here is that only one language can use a toggle
reference on an object or you get a leak.

> IMHO, perhaps instance dictionaries should not be allowed except when
> subclassing.  But I'm not sure the remaining pygtk community would
> feel the same, and I don't think we're allowed to break API
> compatibility like that (the wrath o murray would fall upon us :)

You could probably use a two-part object scheme and overload __setattr__
/__getattr__ to allow instance dictionaries to work without depending
on cyclic GC (except when subclassing). But there is a lot of 
complexity in having separate subclassing / non-subclassing code paths
that seems undesirable.

> Anyway, good to see language bindings given high priority for a
> change.  Keep up the good work :-)

I'm not sure I like that "for a change" :-). Language bindability has
been a big focus of GTK+ since before 1.0.


Attachment: signature.asc
Description: This is a digitally signed message part

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]