[PyKDE] Memory leak: Cycles with QObject's doesn't get collected

Giovanni Bajo rasky at develer.com
Fri Jun 17 17:36:36 BST 2005


Phil Thompson <phil at riverbankcomputing.co.uk> wrote:

>> I think I have found another memory leak. When you create cycles with
>> QObjects they aren't collected. This doesn't happen with pure python
>> objects (as expected), but in that case I have found an strange behaviour
>> when you set the gc.DEBUG_SAVEALL flag (that isn't PyQT related, but take
>> that in account if you add gc debug flags). See the attached script and
>> their logs.
>
> That's because SIP has never supported the cyclic garbage collector. That
is
> now fixed and your test script shows no leak.

I just verified that the same script *does* cause a memory leak if you use
QWidget instead of QObject as test class:

Is GC enabled?: 1
Has TestClass a __del__ method? (if True, it will be marked as unreachable):
False
PY Version:   2.3.4 (#1, Feb  2 2005, 12:11:53)
[GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)]
QT Version:   3.3.4
PYQT Version: snapshot-20050417
SIP Version:  4.2.1 (snapshot-20050430-314)

VmSize: 25320 Kb VmRss: 8732 Kb
VmSize: 25320 Kb VmRss: 8736 Kb
VmSize: 25320 Kb VmRss: 8744 Kb
VmSize: 25320 Kb VmRss: 8748 Kb
VmSize: 25320 Kb VmRss: 8756 Kb
VmSize: 25320 Kb VmRss: 8764 Kb
VmSize: 25320 Kb VmRss: 8768 Kb
VmSize: 25320 Kb VmRss: 8776 Kb
VmSize: 25320 Kb VmRss: 8784 Kb
VmSize: 25320 Kb VmRss: 8788 Kb
VmSize: 25320 Kb VmRss: 8796 Kb
VmSize: 25320 Kb VmRss: 8804 Kb
VmSize: 25320 Kb VmRss: 8808 Kb
VmSize: 25320 Kb VmRss: 8816 Kb
[...]

I have attached the updated script.
-- 
Giovanni Bajo
-------------- next part --------------
#!/usr/bin/env python
from qt import *
import sys, os, gc

######### Query Memory Usage Functions ####################################
def report(s):
    print s
    sys.stdout.flush()

def presentMemData(s=""):
    vmsize = vmrss = 0
    for l in open('/proc/self/status','r').readlines():
        if l.startswith('VmSize:'):
            vmsize = int(l.split()[1])
        elif l.startswith('VmRSS:'):
            vmrss  = int(l.split()[1])
    report(s+"VmSize: %d Kb VmRss: %d Kb" % (vmsize,vmrss))
###########################################################################

import sip
class TestClass(QWidget):
    pass

app = QApplication([])


## Warning, if you uncomment the following line, then the script will leak
## even without using the QObject class. This is because the DEBUG_SAVEALL
## setting is enabled, but is strange because with that flag, only
## unreacheable objects (that is, objects with a __del__ method, see the
## gc module documentation) are saved, and that cant be the case of the
## QObject class or the pure python one.
#gc.set_debug(gc.DEBUG_LEAK | gc.DEBUG_STATS)


# This is enabled by default, just in case.
gc.enable()

# After this setting, gc.collect() will check all the generations
gc.set_threshold(1,1,1)

report("Is GC enabled?: %r" % gc.isenabled())
report("Has TestClass a __del__ method? (if True, it will be marked as unreachable): %r" % hasattr(TestClass(), '__del__'))
report("PY Version:   "+ sys.version)
report("QT Version:   "+ qVersion())
report("PYQT Version: "+ PYQT_VERSION_STR)
report("SIP Version:  "+ os.popen('sip -V').read())
presentMemData()

for i in xrange(100):
    for j in xrange(50):
            a = TestClass(None)
            b = TestClass(None)
            a.payload = ("%r"%a)*100
            a.win = b
            b.win = a
            # uncomment the following line when using QObject to disable the leak
            #b.win = None
            a = None  # redundant
            b = None  # redundant

    gc.collect()
    presentMemData()


More information about the PyQt mailing list