[PyQt] memory leak using QMainWindow.removeToolBar

danny shevitz at lanl.gov
Mon Aug 16 18:27:49 BST 2010


Howdy,

I have run into this curious problem that I think is caused by a memory leak
or improper reference counting related to toolbars in QMainWindow.removeToolBar. 
The problem appears when you remove a toolbar but keep an instance variable
maintaining a reference to the toolbar. I am aware that removeToolBar only
hides the toolbar and does not delete it. I also am aware that the following
code may seem foolish, but it does show the bug. The code below is a minimal
example demonstrating the problem. It is 34 lines long. Simply run the app, and
close via the close box. The app will not close gracefully, but rather seg fault.
This has been validated on windows and Linux.  I don't believe the following
code is doing anything stupid enough to justify a seg fault. The problem
disappears is you remove the instance reference to the toolbar 
(self.editToolBar = editToolBar). Notice that the code is intended to reside
within an SDI framework app like Mark Summerfield uses in his excellent PyQT
book. The instances variables probably keep additional references around that
are part of the problem. Explicitly removing the attribute, gets rid of the 
problem.

Included below is the source code. Please let me know if this is a bug or
my own stupidity.

I am running python 2.5.1, pyqt 4.7.3

thanks,

Danny

#%<--------------------------------------------
import sys
from PyQt4 import QtGui,  QtCore,  QtSql

def isAlive(qobj):
    import sip
    try:
        sip.unwrapinstance(qobj)
    except RuntimeError:
        return False
    return True

class MyApp(QtGui.QMainWindow):
    NextId = 1
    Instances = set()
    
    def __init__(self, parent=None):
        super(MyApp, self).__init__(parent)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        MyApp.Instances.add(self)
        self.editToolBar = self.addToolBar("Edit")
        self.removeToolBar(self.editToolBar)
        # delattr(self,  'editToolBar') # this gets rid of the seg fault
        self.destroyed.connect(MyApp.updateInstances)
        self.setCentralWidget(QtGui.QWidget())             

    @staticmethod
    def updateInstances(qobj):
        MyApp.Instances = set([window for window \
                in MyApp.Instances if isAlive(window)])
                
if __name__=='__main__':
    application = QtGui.QApplication(sys.argv)
    MyApp().show()
    application.exec_()




More information about the PyQt mailing list