Hello,

(Maybe this is not new to you, sorry if it's the case.)

I have been monitoring a big PyQt application lately, trying to reduce memory 
usage. I noticed that QDialog causes memory leaks.

Using C++, one can use a dialog like this:
  void function() {
    MyDialog dlg(this);
    dlg.exec();
  }

The Python equivalent is:

  def function(self):
    dlg=MyDialog(self)
    dlg.exec_loop()

Except that this is not totally equivalent:
- In the C++ version, dlg is a local variable: so it gets deleted when we get 
out of function().
- In the Python version, dlg is owned by self: when we get out of function(), 
it is still referenced and won't get garbage collected. A workaround to that 
problem is to reparent the dialog, like this:

  def function(self):
    dlg=MyDialog(self)
    dlg.exec_loop()
    dlg.reparent(None, QPoint(0,0))

The attached Python example demonstrates this.

If there is a better solution, let me know.
-- 
Aurélien Gâteau - [EMAIL PROTECTED]
Dental-on-line
23 rue du Départ
75014 PARIS - FRANCE
import os
import sys

from qt import *


_statmFile=None
def logMemoryUsage(msg):
    global _statmFile
    if not _statmFile:
        name=os.path.join("/proc", str(os.getpid()), "statm")
        _statmFile=file(name)
    _statmFile.seek(0)
    txt=_statmFile.read().strip()
    lst=txt.split()

    # According to kernel doc, values after the third one are broken
    lst=lst[:3]

    print msg, ",".join(lst)


class Dialog(QDialog):
    def __init__(self, parent):
        QDialog.__init__(self, parent)
        button=QPushButton("Ok", self)
        QObject.connect(button, SIGNAL("clicked()"), self.accept)

        # Allocate some big data to illustrate leak
        self.bigData=[12]*2000000



class Window(QVBox):
    def __init__(self):
        QVBox.__init__(self)
        button=QPushButton("Dialog (no reparent)", self)
        QObject.connect(button, SIGNAL("clicked()"), self.openDialogNoReparent)

        button=QPushButton("Dialog (reparent)", self)
        QObject.connect(button, SIGNAL("clicked()"), self.openDialogReparent)

    def openDialogNoReparent(self):
        logMemoryUsage("Before")
        
        dlg=Dialog(self)
        dlg.exec_loop()
        
        logMemoryUsage("After")
    
    def openDialogReparent(self):
        logMemoryUsage("Before")
        
        dlg=Dialog(self)
        dlg.exec_loop()
        
        logMemoryUsage("After")
        dlg.reparent(None, QPoint(0,0) )
        


def main():
    app=QApplication(sys.argv)
    
    win=Window()
    win.show()
    app.setMainWidget(win)
    app.exec_loop()


if __name__=="__main__":
    main()
_______________________________________________
PyKDE mailing list    [email protected]
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde

Reply via email to