[PyQt] pyqt circular references & garbage collection

Giovanni Bajo rasky at develer.com
Wed Aug 1 11:53:31 BST 2007


On mar, 2007-07-31 at 13:11 -0700, charles chen wrote:

> 
>    Thanks Phil for your help with our memory lapse.
> 
>    We've come across another issue:  the Python garbage collector
> isn't sussing out circular references properly.
> 
>    A previous post by you say that this should be working:
> 
> http://www.riverbankcomputing.com/pipermail/pyqt/2007-May/016237.html
> 
>    Here's a simple demonstration:
> 
> >>> from PyQt4.QtCore import QObject
> >>> class q(QObject):
> ...   def init(self):
> ...     QObject.init(self)
> ...   def __del__(self):
> ...     print 'q deleted.'
> ...
> >>> q1 = q()
> >>> q1 = None
> q deleted.
> >>> q2 = q(
> >>> q2.circularReference = q2
> >>> q2 = None
> >>> q3 = q()
> >>> q3.circularReference = q3
> >>> q3.deleteLater()
> >>> q3 = None
> >>> import gc
> >>> gc.collect()
> 0
> >>> q4 = q()
> >>> q4.circularReference = q4
> >>> q4.circularReference = None
> >>> q4 = None
> q deleted.
> 
>    q2 and q3 are never gc'ed.
> 
>    We're also seeing this in production.  Are we doing something
> wrong?  

Yes the garbage collector doesn't work with objects containing __del__.
That's true since GC was introduced in Python 2.0. If you activate GC
debug mode (via gc.set_flags() or whatever it is called), run an
explicit gc.collect() call, and look at gc.garbage, you should find your
q2 and q3 there, as they are classified as "uncollectable"  

Try rewriting your example without __del__ and it will work. To issue a
pring when an object is collected without using __del__, you have 2
alternatives:

a) Use Python's weakref, which allows to register a callback function
invoked when an object is about to be collected.
b) Use Qt's SIGNAL("destroyed()"), emitted by all QObjects when they are
in the process of being destroyed.

Either way, you will see that your objects are collected. 

Notice that using a weakref internally within a class is a good way to
replace existing code using __del__ and make it GC-friendly.
-- 
Giovanni Bajo




More information about the PyQt mailing list