[PyQt] Realizing memory used by signals with objects

Jan Kotanski jan.kotanski at desy.de
Thu Apr 16 10:59:39 BST 2015


Hi,

I've just tested memory leaks in my application and I've accounted
a problem how to realize memory used by signals with objects, e.g.
QSignalMapper.mapped signal with a QWidget parameter.
After disconnecting this signal using garbage collector one can find
that PyQt leaves a weakref in the memory.
If I change the QWidget parameter to an int parameter this problem
disappears.

I've tested this issue in PyQt 4.9.3 (wheezy), 4.11.2 (jessie),  5.3.2
(jessie).

Is there any way to remove this weak reference (except catching it by gc)?

Bellow I append my test script for PyQt4.

Thanks,
Jan


from PyQt4.QtGui import (QWidget, QPushButton, QDialog, QVBoxLayout)
from PyQt4.QtCore import (QSignalMapper, pyqtSlot, QObject)

import sys
import gc
from collections import Counter


class Con(QObject):
    def __init__(self, parent=None):
        super(Con, self).__init__(parent)
        self.mapper = QSignalMapper(self)
        self.mapper.mapped.connect(self.checked)

    @pyqtSlot(QWidget)
#    @pyqtSlot(int)
    def checked(self, widget):
        print( "TYPE: %s" % type(widget))

    def close(self):
        self.mapper.mapped.disconnect(self.checked)
        self.mapper.setParent(None)
        self.mapper = None


class Dialog(QDialog):
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)
        self.button = QPushButton("Run")
        vbl = QVBoxLayout()
        vbl.addWidget(self.button)
        self.con = None
        self.setLayout(vbl)
        self.button.clicked.connect(self.reset)

    def test(self):
        self.con = Con(self)
        self.con.close()
        self.con.setParent(None)
        del self.con
        self.con = None

    @pyqtSlot()
    def reset(self):
        for i in range(1000):
            self.test()
            gc.collect()
            print ("i = %s #OBJ = %s: %s" % (
                i, len(gc.get_objects()),
                Counter([type(g).__name__ for g in gc.get_objects()]
                    ).most_common(4)))


def main():
    from PyQt4.QtGui import QApplication
    app = QApplication(sys.argv)
    form = Dialog()
    form.show()
    app.exec_()

if __name__ == "__main__":
    main()


More information about the PyQt mailing list