3

I'm doing a project using Qt with some customized QDialogs for user input. Due to hardware constraint of my development box, I want to monitor the memory usage of my app. How I exec the dialog.

1 void MainWindow::callDialog() {
2     DlgPopConfig dialog(&theApp->cfgPop, m_fnPopCfg, this);
3     dialog.exec();
4     m_fnPopCfg = dialog.fileName();
5     lbl_fnPopCfg->setText(m_fnPopCfg);
6 }

As the dialog is a local variable, I expect it to be created on stack and destroy immediately once the function ends (after line 5). When the app repeatedly open and close the dialog, its mem usage goes up, and it never return to initial values ['Memory (Working Set)' and 'Memory (Private Working Set)' columns of Task Manager]. I used Application Verifier, enabling all the basic tests, and it shows no error'. The memory pattern looks like follow (numeric values are made-up of illustration only):

  • Application start (working set = 12000K, private set = 6000K)
  • Open Dialog-1 (working set = 14000K, private set = 7000K)
  • Close Dialog (working set = 12010K, private set = 6005K)
  • Open Dialog-2 (working set = 14020K, private set = 7000K)
  • Close Dialog (working set = 12010K, private set = 6008K)
  • Open Dialog-3 (working set = 14080K, private set = 7010K)
  • Close Dialog (working set = 12040K, private set = 6008K)
  • ...

So, any idea to trace the root cause of the problem? (Actually, I'm also facing similar issue when usage static methods of QFileDialog getOpenFileName, getSaveFileName, and found some discussion here, but it seems not solved)

Edit I use QFormLayout in my dialogs, and I add widgets by layout->addRow("label text", mywidget);, I doubt if the object destruction fail to remove the labels cleanly.

Edit I created a test program with the QDialog have ten QLineEdits, using same add-widget strategy. The problem still exists. (The problem will happen for this test program if I create and close the dialog frequently, says 10 times in a second)

mainwindow.h

#include <QMainWindow>
#include <QPushButton>
#include <QDialog>
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
private:
    QPushButton * button;
private slots:
    void button_click();
};
class Dialog : public QDialog
{
    Q_OBJECT
public:
    explicit Dialog(QWidget *parent = 0);
};

mainwindow.cpp

#include "mainwindow.h"
#include <QApplication>
#include <QFormLayout>
#include <QLineEdit>
#include <QLabel>

MainWindow::MainWindow(QWidget *parent):QMainWindow(parent)
{
    button=new QPushButton(this);setCentralWidget(button);
    connect(button,SIGNAL(clicked()),SLOT(button_click()));
}
void MainWindow::button_click()
{
    Dialog d(this);
    d.exec();
}
Dialog::Dialog(QWidget *parent):QDialog(parent)
{
   QFormLayout*layout=new QFormLayout(this);
   setLayout(layout);
   for (int i = 0; i < 10; i++)
   {
       layout->addRow(QString("%1").arg(i+1), new QLineEdit(this));
   }
}
int main(int c,char *argv[])
{
    QApplication a(c,argv);
    MainWindow w;
    w.show();
    return a.exec();
}

Platform

  • Win 7 x64, MinGW 4.7.2 x64 (rubenvb-build), 4GB ram
  • Qt 4.8.5 (built natively using above tool-chain)
  • Qt-Creator 2.6.1 (built natively using above tool-chain)
YamHon.CHAN
  • 866
  • 4
  • 20
  • 36
  • It's definitely not how you create the dialog, that looks fine. So it must be in DlgPopConfig. widgets inside other widgets are safe (parent/child hierarchy). Try if you get the same with a standard widget (QDialog, for example). If you have access to OS X or Linux, run it in valgrind. – Frank Osterfeld Mar 28 '13 at 05:37
  • Qt 4.8.5? Is it a beta? Try 4.8.4 or 4.7.4. Your test app looks fine, so it can be a qt issue. – Amartel Mar 28 '13 at 06:34
  • @Amartel, 'Qt 4.8.5' is noticed from the about box of my QtCreator. My development box has only 1 set of Qt (as building the 64bit library takes days) Actually, I downloaded the master.tar.gz from qt.gitorious.org directly and built from that. – YamHon.CHAN Mar 28 '13 at 06:48
  • If you look at your private set (which is an actual memory consumption), closing your second and third dialogs leads to the exact number. Can you collect more statistics (at least 5-6 show/close cycles of your dialog)? – Amartel Mar 28 '13 at 06:57

1 Answers1

3

A few months late, but this might help the next person who comes across this problem. I'm using PySide, but had the same memory leak. There turned out to be two options, depending on what information you need to get back from the dialog:

1) Schedule the dialog for deletion when you're done with it.

In Python, this looks like:

dialog = MyDialog(self)
dialog.exec_()
# Do other things with dialog
dialog.deleteLater()

And it should look similar in your C++ code:

void MainWindow::button_click()
{
    Dialog d(this);
    d.exec();
    // Do other things with d
    d.deleteLater()
}

2) Set the WA_DeleteOnClose attribute.

I ended up including this in the custom dialog's constructor:

    self.setAttribute(PySide.QtCore.Qt.WA_DeleteOnClose)

Which should look something like this in your C++ code:

Dialog::Dialog(QWidget *parent):QDialog(parent)
{
   QFormLayout*layout=new QFormLayout(this);
   setLayout(layout);
   setAttribute(Qt::WA_DeleteOnClose);
   for (int i = 0; i < 10; i++)
   {
       layout->addRow(QString("%1").arg(i+1), new QLineEdit(this));
   }
}

Both of those fixed the memory leak for me, except that it will occasionally leak 4kb if I open/close the dialog very quickly a bunch of times in a row. Sorry for the Python-centric answer -- hopefully this points people in the right direction.

Max Fellows
  • 382
  • 3
  • 9