PyGTK object escapes garbage collection

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

PyGTK object escapes garbage collection

Pierre-91
Hello list,

I run into a surprising behavior regarding garbage collection. In the
following example, a Notebook page is removed from its parent widget and
destroyed. However, the page is not garbage-collected unless the "tab"
widget (a gtk.HBox) is first destroyed.

Only the Page instance refers to the "tab" widget. Besides, "tab" is
indirectly associated to the page: one of its child widget's signal is
connected to a Page method. So we have something like this:

   page --> tab --> button --> callback --> page --> tab --> etc.

Once remove_page() returns, I would expect tab and page to be destroyed
and collected, because both objects become unreachable (unreachable
through Python variables and GTK calls). But the gc module shows that
they are not collected.

Is this the expected behavior ?  I'm using pygtk 2.17.0, gtk 2.20.1, and
Python 2.6.6.

Thank you for your time.

Pierre


# ------------------------------------------------------ #

import gc
import gtk
import gobject

DESTROY_TAB = False

class Page(gtk.VBox):

     def __init__(self):
         gtk.VBox.__init__(self)
         self.pack_start(gtk.TextView(), True, True) # To fill the window
         button = gtk.Button()
         button.connect("clicked", self.hello)
         title = gtk.Label("hello")
         tab = gtk.HBox()
         tab.pack_start(title, True, True)
         tab.pack_end(button, False, False)
         tab.show_all()

         # Keeping a reference here is the culprit. Could it be a
         # circular reference problem ?
         # tab --> button --> hello --> page --> tab --> ...
         self.tab = tab

     def hello(self, widget):
         print "hello"

def add_page(notebook):
     print "Adding a page to the Notebook."
     page = Page()
     page.show_all()
     notebook.append_page(page, tab_label=page.tab)

def remove_page(notebook):
     print "Removing the page."
     page = notebook.get_nth_page(0)
     notebook.remove_page(0)
     page.destroy()
     # Destroying page.tab let the GC collect the page.
     if DESTROY_TAB:
         page.tab.destroy()

def main():
     notebook = gtk.Notebook()
     w = gtk.Window()
     w.add(notebook)
     w.resize(400, 400)
     w.show_all()
     w.connect("destroy", gtk.main_quit)
     gobject.idle_add(add_page, notebook)
     gobject.timeout_add(1000, remove_page, notebook)
     gobject.timeout_add(2000, gtk.main_quit)
     gtk.main()

def seek_page():
     gc.collect()
     oo = gc.get_objects()
     for o in oo:
         if hasattr(o, "__class__") and (o.__class__ is Page
                                         or o.__class__ is gtk.HBox):
             print
             print o, "escaped garbage collection"
             print 'Referrers are :'
             for r in gc.get_referrers(o):
                 print '  *', repr(r)[:65], '...'


main()
seek_page()


# Output:
# ------
#
# Adding a page to the Notebook.
# Removing the page.
#
# <Page object at 0x98a898c (GtkVBox at 0x9960c18)> escaped garbage
collection
# Referrers are :
#   * [(), {'__setattr__': <slot wrapper '__setattr__' of 'object' obje ...
#   * <bound method Page.hello of <Page object at 0x98a898c (GtkVBox at ...
#   * <frame object at 0x999f68c> ...
#
# <gtk.HBox object at 0x98a8a04 (GtkHBox at 0x9960c70)> escaped garbage
collection
# Referrers are :
#   * [(), {'__setattr__': <slot wrapper '__setattr__' of 'object' obje ...
#   * <frame object at 0x999f68c> ...
#   * {'tab': <gtk.HBox object at 0x98a8a04 (GtkHBox at 0x9960c70)>} ...
_______________________________________________
pygtk mailing list   [hidden email]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/
Reply | Threaded
Open this post in threaded view
|

Re: PyGTK object escapes garbage collection

Gerald Britton-2
We encountered this problem in our project (gramps-project.org).  It
took quite a bit of work to remove the refs to allow GC. Basically, we
added code to track the callbacks then, when the objects were deleted,
added code to explicitly remove them (delete them or set them to None)
to break the cyclical refs.  Also, we added code to delete (or set to
None) attributes that might possibly be involved in the cycle.

It was a lot of work but we eventually stopped the memory leaks.
Still, I believe that pygtk could be a LOT smarter in this regard.  I
think that what we had to do amounts to fixing a serious design issue
in pygtk.

On Tue, Dec 21, 2010 at 12:16 PM, Pierre <[hidden email]> wrote:

> Hello list,
>
> I run into a surprising behavior regarding garbage collection. In the
> following example, a Notebook page is removed from its parent widget and
> destroyed. However, the page is not garbage-collected unless the "tab"
> widget (a gtk.HBox) is first destroyed.
>
> Only the Page instance refers to the "tab" widget. Besides, "tab" is
> indirectly associated to the page: one of its child widget's signal is
> connected to a Page method. So we have something like this:
>
>  page --> tab --> button --> callback --> page --> tab --> etc.
>
> Once remove_page() returns, I would expect tab and page to be destroyed and
> collected, because both objects become unreachable (unreachable through
> Python variables and GTK calls). But the gc module shows that they are not
> collected.
>
> Is this the expected behavior ?  I'm using pygtk 2.17.0, gtk 2.20.1, and
> Python 2.6.6.
>
> Thank you for your time.
>
> Pierre
>
>
> # ------------------------------------------------------ #
>
> import gc
> import gtk
> import gobject
>
> DESTROY_TAB = False
>
> class Page(gtk.VBox):
>
>    def __init__(self):
>        gtk.VBox.__init__(self)
>        self.pack_start(gtk.TextView(), True, True) # To fill the window
>        button = gtk.Button()
>        button.connect("clicked", self.hello)
>        title = gtk.Label("hello")
>        tab = gtk.HBox()
>        tab.pack_start(title, True, True)
>        tab.pack_end(button, False, False)
>        tab.show_all()
>
>        # Keeping a reference here is the culprit. Could it be a
>        # circular reference problem ?
>        # tab --> button --> hello --> page --> tab --> ...
>        self.tab = tab
>
>    def hello(self, widget):
>        print "hello"
>
> def add_page(notebook):
>    print "Adding a page to the Notebook."
>    page = Page()
>    page.show_all()
>    notebook.append_page(page, tab_label=page.tab)
>
> def remove_page(notebook):
>    print "Removing the page."
>    page = notebook.get_nth_page(0)
>    notebook.remove_page(0)
>    page.destroy()
>    # Destroying page.tab let the GC collect the page.
>    if DESTROY_TAB:
>        page.tab.destroy()
>
> def main():
>    notebook = gtk.Notebook()
>    w = gtk.Window()
>    w.add(notebook)
>    w.resize(400, 400)
>    w.show_all()
>    w.connect("destroy", gtk.main_quit)
>    gobject.idle_add(add_page, notebook)
>    gobject.timeout_add(1000, remove_page, notebook)
>    gobject.timeout_add(2000, gtk.main_quit)
>    gtk.main()
>
> def seek_page():
>    gc.collect()
>    oo = gc.get_objects()
>    for o in oo:
>        if hasattr(o, "__class__") and (o.__class__ is Page
>                                        or o.__class__ is gtk.HBox):
>            print
>            print o, "escaped garbage collection"
>            print 'Referrers are :'
>            for r in gc.get_referrers(o):
>                print '  *', repr(r)[:65], '...'
>
>
> main()
> seek_page()
>
>
> # Output:
> # ------
> #
> # Adding a page to the Notebook.
> # Removing the page.
> #
> # <Page object at 0x98a898c (GtkVBox at 0x9960c18)> escaped garbage
> collection
> # Referrers are :
> #   * [(), {'__setattr__': <slot wrapper '__setattr__' of 'object' obje ...
> #   * <bound method Page.hello of <Page object at 0x98a898c (GtkVBox at ...
> #   * <frame object at 0x999f68c> ...
> #
> # <gtk.HBox object at 0x98a8a04 (GtkHBox at 0x9960c70)> escaped garbage
> collection
> # Referrers are :
> #   * [(), {'__setattr__': <slot wrapper '__setattr__' of 'object' obje ...
> #   * <frame object at 0x999f68c> ...
> #   * {'tab': <gtk.HBox object at 0x98a8a04 (GtkHBox at 0x9960c70)>} ...
> _______________________________________________
> pygtk mailing list   [hidden email]
> http://www.daa.com.au/mailman/listinfo/pygtk
> Read the PyGTK FAQ: http://faq.pygtk.org/
>



--
Gerald Britton
_______________________________________________
pygtk mailing list   [hidden email]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/
Reply | Threaded
Open this post in threaded view
|

Re: PyGTK object escapes garbage collection

Arjan Molenaar-3

Small question, are the items that are not collected in the destroyed state?

Regards, Arjan

Op 23 dec. 2010 16:02 schreef "Gerald Britton" <[hidden email]> het volgende:
> We encountered this problem in our project (gramps-project.org). It
> took quite a bit of work to remove the refs to allow GC. Basically, we
> added code to track the callbacks then, when the objects were deleted,
> added code to explicitly remove them (delete them or set them to None)
> to break the cyclical refs. Also, we added code to delete (or set to
> None) attributes that might possibly be involved in the cycle.
>
> It was a lot of work but we eventually stopped the memory leaks.
> Still, I believe that pygtk could be a LOT smarter in this regard. I
> think that what we had to do amounts to fixing a serious design issue
> in pygtk.
>
> On Tue, Dec 21, 2010 at 12:16 PM, Pierre <[hidden email]> wrote:
>> Hello list,
>>
>> I run into a surprising behavior regarding garbage collection. In the
>> following example, a Notebook page is removed from its parent widget and
>> destroyed. However, the page is not garbage-collected unless the "tab"
>> widget (a gtk.HBox) is first destroyed.
>>
>> Only the Page instance refers to the "tab" widget. Besides, "tab" is
>> indirectly associated to the page: one of its child widget's signal is
>> connected to a Page method. So we have something like this:
>>
>>  page --> tab --> button --> callback --> page --> tab --> etc.
>>
>> Once remove_page() returns, I would expect tab and page to be destroyed and
>> collected, because both objects become unreachable (unreachable through
>> Python variables and GTK calls). But the gc module shows that they are not
>> collected.
>>
>> Is this the expected behavior ?  I'm using pygtk 2.17.0, gtk 2.20.1, and
>> Python 2.6.6.
>>
>> Thank you for your time.
>>
>> Pierre
>>
>>
>> # ------------------------------------------------------ #
>>
>> import gc
>> import gtk
>> import gobject
>>
>> DESTROY_TAB = False
>>
>> class Page(gtk.VBox):
>>
>>    def __init__(self):
>>        gtk.VBox.__init__(self)
>>        self.pack_start(gtk.TextView(), True, True) # To fill the window
>>        button = gtk.Button()
>>        button.connect("clicked", self.hello)
>>        title = gtk.Label("hello")
>>        tab = gtk.HBox()
>>        tab.pack_start(title, True, True)
>>        tab.pack_end(button, False, False)
>>        tab.show_all()
>>
>>        # Keeping a reference here is the culprit. Could it be a
>>        # circular reference problem ?
>>        # tab --> button --> hello --> page --> tab --> ...
>>        self.tab = tab
>>
>>    def hello(self, widget):
>>        print "hello"
>>
>> def add_page(notebook):
>>    print "Adding a page to the Notebook."
>>    page = Page()
>>    page.show_all()
>>    notebook.append_page(page, tab_label=page.tab)
>>
>> def remove_page(notebook):
>>    print "Removing the page."
>>    page = notebook.get_nth_page(0)
>>    notebook.remove_page(0)
>>    page.destroy()
>>    # Destroying page.tab let the GC collect the page.
>>    if DESTROY_TAB:
>>        page.tab.destroy()
>>
>> def main():
>>    notebook = gtk.Notebook()
>>    w = gtk.Window()
>>    w.add(notebook)
>>    w.resize(400, 400)
>>    w.show_all()
>>    w.connect("destroy", gtk.main_quit)
>>    gobject.idle_add(add_page, notebook)
>>    gobject.timeout_add(1000, remove_page, notebook)
>>    gobject.timeout_add(2000, gtk.main_quit)
>>    gtk.main()
>>
>> def seek_page():
>>    gc.collect()
>>    oo = gc.get_objects()
>>    for o in oo:
>>        if hasattr(o, "__class__") and (o.__class__ is Page
>>                                        or o.__class__ is gtk.HBox):
>>            print
>>            print o, "escaped garbage collection"
>>            print 'Referrers are :'
>>            for r in gc.get_referrers(o):
>>                print '  *', repr(r)[:65], '...'
>>
>>
>> main()
>> seek_page()
>>
>>
>> # Output:
>> # ------
>> #
>> # Adding a page to the Notebook.
>> # Removing the page.
>> #
>> # <Page object at 0x98a898c (GtkVBox at 0x9960c18)> escaped garbage
>> collection
>> # Referrers are :
>> #   * [(), {'__setattr__': <slot wrapper '__setattr__' of 'object' obje ...
>> #   * <bound method Page.hello of <Page object at 0x98a898c (GtkVBox at ...
>> #   * <frame object at 0x999f68c> ...
>> #
>> # <gtk.HBox object at 0x98a8a04 (GtkHBox at 0x9960c70)> escaped garbage
>> collection
>> # Referrers are :
>> #   * [(), {'__setattr__': <slot wrapper '__setattr__' of 'object' obje ...
>> #   * <frame object at 0x999f68c> ...
>> #   * {'tab': <gtk.HBox object at 0x98a8a04 (GtkHBox at 0x9960c70)>} ...
>> _______________________________________________
>> pygtk mailing list   [hidden email]
>> http://www.daa.com.au/mailman/listinfo/pygtk
>> Read the PyGTK FAQ: http://faq.pygtk.org/
>>
>
>
>
> --
> Gerald Britton
> _______________________________________________
> pygtk mailing list [hidden email]
> http://www.daa.com.au/mailman/listinfo/pygtk
> Read the PyGTK FAQ: http://faq.pygtk.org/

_______________________________________________
pygtk mailing list   [hidden email]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/
Reply | Threaded
Open this post in threaded view
|

Re: PyGTK object escapes garbage collection

Gerald Britton-2
In reply to this post by Pierre-91
I patched your code to use weakref like this:
...
import weakref
...
def __init__...
...
       button.connect("clicked", weakref.proxy(self.hello))
...

When I did that, there was nothing in the gc.get_referrers list at the
end.  If I understand this correctly, pygtk's reference to self.hello
was weak and didn't increment the ref counter, so when the page was
destroyed it was gc'd.

Would that work for you?




On Tue, Dec 21, 2010 at 12:16 PM, Pierre <[hidden email]> wrote:

> Hello list,
>
> I run into a surprising behavior regarding garbage collection. In the
> following example, a Notebook page is removed from its parent widget and
> destroyed. However, the page is not garbage-collected unless the "tab"
> widget (a gtk.HBox) is first destroyed.
>
> Only the Page instance refers to the "tab" widget. Besides, "tab" is
> indirectly associated to the page: one of its child widget's signal is
> connected to a Page method. So we have something like this:
>
>  page --> tab --> button --> callback --> page --> tab --> etc.
>
> Once remove_page() returns, I would expect tab and page to be destroyed and
> collected, because both objects become unreachable (unreachable through
> Python variables and GTK calls). But the gc module shows that they are not
> collected.
>
> Is this the expected behavior ?  I'm using pygtk 2.17.0, gtk 2.20.1, and
> Python 2.6.6.
>
> Thank you for your time.
>
> Pierre
>
>
> # ------------------------------------------------------ #
>
> import gc
> import gtk
> import gobject
>
> DESTROY_TAB = False
>
> class Page(gtk.VBox):
>
>    def __init__(self):
>        gtk.VBox.__init__(self)
>        self.pack_start(gtk.TextView(), True, True) # To fill the window
>        button = gtk.Button()
>        button.connect("clicked", self.hello)
>        title = gtk.Label("hello")
>        tab = gtk.HBox()
>        tab.pack_start(title, True, True)
>        tab.pack_end(button, False, False)
>        tab.show_all()
>
>        # Keeping a reference here is the culprit. Could it be a
>        # circular reference problem ?
>        # tab --> button --> hello --> page --> tab --> ...
>        self.tab = tab
>
>    def hello(self, widget):
>        print "hello"
>
> def add_page(notebook):
>    print "Adding a page to the Notebook."
>    page = Page()
>    page.show_all()
>    notebook.append_page(page, tab_label=page.tab)
>
> def remove_page(notebook):
>    print "Removing the page."
>    page = notebook.get_nth_page(0)
>    notebook.remove_page(0)
>    page.destroy()
>    # Destroying page.tab let the GC collect the page.
>    if DESTROY_TAB:
>        page.tab.destroy()
>
> def main():
>    notebook = gtk.Notebook()
>    w = gtk.Window()
>    w.add(notebook)
>    w.resize(400, 400)
>    w.show_all()
>    w.connect("destroy", gtk.main_quit)
>    gobject.idle_add(add_page, notebook)
>    gobject.timeout_add(1000, remove_page, notebook)
>    gobject.timeout_add(2000, gtk.main_quit)
>    gtk.main()
>
> def seek_page():
>    gc.collect()
>    oo = gc.get_objects()
>    for o in oo:
>        if hasattr(o, "__class__") and (o.__class__ is Page
>                                        or o.__class__ is gtk.HBox):
>            print
>            print o, "escaped garbage collection"
>            print 'Referrers are :'
>            for r in gc.get_referrers(o):
>                print '  *', repr(r)[:65], '...'
>
>
> main()
> seek_page()
>
>
> # Output:
> # ------
> #
> # Adding a page to the Notebook.
> # Removing the page.
> #
> # <Page object at 0x98a898c (GtkVBox at 0x9960c18)> escaped garbage
> collection
> # Referrers are :
> #   * [(), {'__setattr__': <slot wrapper '__setattr__' of 'object' obje ...
> #   * <bound method Page.hello of <Page object at 0x98a898c (GtkVBox at ...
> #   * <frame object at 0x999f68c> ...
> #
> # <gtk.HBox object at 0x98a8a04 (GtkHBox at 0x9960c70)> escaped garbage
> collection
> # Referrers are :
> #   * [(), {'__setattr__': <slot wrapper '__setattr__' of 'object' obje ...
> #   * <frame object at 0x999f68c> ...
> #   * {'tab': <gtk.HBox object at 0x98a8a04 (GtkHBox at 0x9960c70)>} ...
> _______________________________________________
> pygtk mailing list   [hidden email]
> http://www.daa.com.au/mailman/listinfo/pygtk
> Read the PyGTK FAQ: http://faq.pygtk.org/
>



--
Gerald Britton
_______________________________________________
pygtk mailing list   [hidden email]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/
Reply | Threaded
Open this post in threaded view
|

Re: PyGTK object escapes garbage collection

Gerald Britton-2
In reply to this post by Pierre-91
I patched your code to use weakref like this:
...
import weakref
...
def __init__...
...
      button.connect("clicked", weakref.proxy(self.hello))
...

When I did that, there was nothing in the gc.get_referrers list at the
end.  If I understand this correctly, pygtk's reference to self.hello
was weak and didn't increment the ref counter, so when the page was
destroyed it was gc'd.

Would that work for you?

On Tue, Dec 21, 2010 at 12:16 PM, Pierre <[hidden email]> wrote:

> Hello list,
>
> I run into a surprising behavior regarding garbage collection. In the
> following example, a Notebook page is removed from its parent widget and
> destroyed. However, the page is not garbage-collected unless the "tab"
> widget (a gtk.HBox) is first destroyed.
>
> Only the Page instance refers to the "tab" widget. Besides, "tab" is
> indirectly associated to the page: one of its child widget's signal is
> connected to a Page method. So we have something like this:
>
>  page --> tab --> button --> callback --> page --> tab --> etc.
>
> Once remove_page() returns, I would expect tab and page to be destroyed and
> collected, because both objects become unreachable (unreachable through
> Python variables and GTK calls). But the gc module shows that they are not
> collected.
>
> Is this the expected behavior ?  I'm using pygtk 2.17.0, gtk 2.20.1, and
> Python 2.6.6.
>
> Thank you for your time.
>
> Pierre
>
>
> # ------------------------------------------------------ #
>
> import gc
> import gtk
> import gobject
>
> DESTROY_TAB = False
>
> class Page(gtk.VBox):
>
>    def __init__(self):
>        gtk.VBox.__init__(self)
>        self.pack_start(gtk.TextView(), True, True) # To fill the window
>        button = gtk.Button()
>        button.connect("clicked", self.hello)
>        title = gtk.Label("hello")
>        tab = gtk.HBox()
>        tab.pack_start(title, True, True)
>        tab.pack_end(button, False, False)
>        tab.show_all()
>
>        # Keeping a reference here is the culprit. Could it be a
>        # circular reference problem ?
>        # tab --> button --> hello --> page --> tab --> ...
>        self.tab = tab
>
>    def hello(self, widget):
>        print "hello"
>
> def add_page(notebook):
>    print "Adding a page to the Notebook."
>    page = Page()
>    page.show_all()
>    notebook.append_page(page, tab_label=page.tab)
>
> def remove_page(notebook):
>    print "Removing the page."
>    page = notebook.get_nth_page(0)
>    notebook.remove_page(0)
>    page.destroy()
>    # Destroying page.tab let the GC collect the page.
>    if DESTROY_TAB:
>        page.tab.destroy()
>
> def main():
>    notebook = gtk.Notebook()
>    w = gtk.Window()
>    w.add(notebook)
>    w.resize(400, 400)
>    w.show_all()
>    w.connect("destroy", gtk.main_quit)
>    gobject.idle_add(add_page, notebook)
>    gobject.timeout_add(1000, remove_page, notebook)
>    gobject.timeout_add(2000, gtk.main_quit)
>    gtk.main()
>
> def seek_page():
>    gc.collect()
>    oo = gc.get_objects()
>    for o in oo:
>        if hasattr(o, "__class__") and (o.__class__ is Page
>                                        or o.__class__ is gtk.HBox):
>            print
>            print o, "escaped garbage collection"
>            print 'Referrers are :'
>            for r in gc.get_referrers(o):
>                print '  *', repr(r)[:65], '...'
>
>
> main()
> seek_page()
>
>
> # Output:
> # ------
> #
> # Adding a page to the Notebook.
> # Removing the page.
> #
> # <Page object at 0x98a898c (GtkVBox at 0x9960c18)> escaped garbage
> collection
> # Referrers are :
> #   * [(), {'__setattr__': <slot wrapper '__setattr__' of 'object' obje ...
> #   * <bound method Page.hello of <Page object at 0x98a898c (GtkVBox at ...
> #   * <frame object at 0x999f68c> ...
> #
> # <gtk.HBox object at 0x98a8a04 (GtkHBox at 0x9960c70)> escaped garbage
> collection
> # Referrers are :
> #   * [(), {'__setattr__': <slot wrapper '__setattr__' of 'object' obje ...
> #   * <frame object at 0x999f68c> ...
> #   * {'tab': <gtk.HBox object at 0x98a8a04 (GtkHBox at 0x9960c70)>} ...
> _______________________________________________
> pygtk mailing list   [hidden email]
> http://www.daa.com.au/mailman/listinfo/pygtk
> Read the PyGTK FAQ: http://faq.pygtk.org/
>



--
Gerald Britton
_______________________________________________
pygtk mailing list   [hidden email]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/
Reply | Threaded
Open this post in threaded view
|

Re: PyGTK object escapes garbage collection

Pierre-91
Thanks for your answers Gerald.

>        button.connect("clicked", weakref.proxy(self.hello))

Well, I get this when I click the button:

    ReferenceError: weakly-referenced object no longer exists

That's surprising too, since the hello() method of "page" certainly does
exist until "page" gets unreachable... and, at the time I click, "page"
can be reached through the notebook.get_nth_page() method.

Unfortunately, I'm not familiar enough with how the Python and the
GObject reference counting systems interact to understand what's going on.

I will wait for more answers, then submit a bug report.

Cheers,
Pierre
_______________________________________________
pygtk mailing list   [hidden email]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/
Reply | Threaded
Open this post in threaded view
|

Re: PyGTK object escapes garbage collection

Hrvoje Niksic-2
In reply to this post by Pierre-91
The problem you describe sounds like it might be related to this
infamous PyGTK bug:

https://bugzilla.gnome.org/show_bug.cgi?id=546802

In our tests the problems show up when a Python object that participates
in a cycle is referenced only through a GTK widget.  When GC takes
place, Python's cycle-breaker incorrectly concludes that the whole cycle
is unreachable and runs tp_clear on all objects.  The objects are, of
course, still reachable through PyGTK, and unfortunately now quite broken.

A number of workarounds are available: simply access the widget's
__dict__, which forces it to switch to a different reference-counting
strategy.  Or store a reference to your object in a global variable or
container.
_______________________________________________
pygtk mailing list   [hidden email]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/
Reply | Threaded
Open this post in threaded view
|

Re: PyGTK object escapes garbage collection

Gerald Britton-2
On Fri, Dec 24, 2010 at 5:28 AM, Hrvoje Niksic <[hidden email]> wrote:

> The problem you describe sounds like it might be related to this infamous
> PyGTK bug:
>
> https://bugzilla.gnome.org/show_bug.cgi?id=546802
>
> In our tests the problems show up when a Python object that participates in
> a cycle is referenced only through a GTK widget.  When GC takes place,
> Python's cycle-breaker incorrectly concludes that the whole cycle is
> unreachable and runs tp_clear on all objects.  The objects are, of course,
> still reachable through PyGTK, and unfortunately now quite broken.
>
> A number of workarounds are available: simply access the widget's __dict__,
> which forces it to switch to a different reference-counting strategy.  Or
> store a reference to your object in a global variable or container.

To me, this is clearly a pygtk bug.  It should not be creating cycles
like this.  Also, it can create cycles without your participation.  If
you use builder, it can find callbacks using introspection.  I have
some modules that use introspection and have a few "connect" calls as
well.  To have to do all the introspection yourself in your own
modules is ridiculous.



> _______________________________________________
> pygtk mailing list   [hidden email]
> http://www.daa.com.au/mailman/listinfo/pygtk
> Read the PyGTK FAQ: http://faq.pygtk.org/
>



--
Gerald Britton
_______________________________________________
pygtk mailing list   [hidden email]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/