Memory Leaks with QDialog ans QPushButton
-
Hi!
I work on a personal project, and I use Qt to handle the UI. I tried recently to use some QDialog for some simple actions on my application. I have no problem when they are modal, but (when they are not) I found a memory leak.
When I create a non-modal QDialog with a QPushButton inside in my application and I close the application without closing the QDialog (by a mouse click on the close button or a call of close() method) I have a memory leak from Qt but I can't find where it comes from.I had redirected all the memory used by Qt in my own memory manager by overloading qMalloc, qFree, etc. and the new and delete operators. My memory manager is created before the Qt initialization thanks to a static variable and shutdown after the Qt's shutdown.
This is the log I get from my memory manager, the d:[…]\mem.cpp(154) indicate that the file and the line where the leaked memory had been allocated and it's in my overloaded qMalloc.
[ERROR]
d:[…]\mem.cpp(154): Memory leak detected of 16 bytes at address 0×005c1d80.[ERROR]
d:[…]\mem.cpp(154): Memory leak detected of 16 bytes at address 0×005c1e40.[ERROR]
d:[…]\mem.cpp(154): Memory leak detected of 56 bytes at address 0×005c1e80.[ERROR]
d:[…]\mem.cpp(154): Memory leak detected of 88 bytes at address 0×005c4af0.[ERROR]
d:[…]\mem.cpp(154): Memory leak detected of 88 bytes at address 0×00e0fcd0.[ERROR]
d:[…]\mem.cpp(154): Memory leak detected of 88 bytes at address 0×00e0fd90.To test if the leak come from a side effect of other Qt's usages, I made a simplified version of the issue and I get exactly the same memory leaks. This is my simplified version. It creates an QApplication, which creates a QMainWindow which creates a QDialog with a QPushButton inside.
Memory redirection:
@void *qMalloc(size_t size)
{
return MY_ALLOC(size,AID_QT);
}...
@My QMainWindow:
- qdialogtestwindow.h
@#ifndef GUI_QT_DIALOG_TEST_WINDOW_H
#define GUI_QT_DIALOG_TEST_WINDOW_H#include <QtGui/QMainWindow>
class QDialog;
class QFormLayout;
class QPushButton;
class QMenuBar;
class QMenu;
class QAction;class QDialogTestWindow : public QMainWindow
{
Q_OBJECTpublic:
QDialogTestWindow(QWidget *parent = 0, Qt::WFlags flags = 0);
~QDialogTestWindow(void);void Initialize();
protected slots:
virtual void closeEvent(QCloseEvent *e);private:
QDialog* m_qDialog;
QAction* m_action;
};
#endif //GUI_QT_DIALOG_TEST_WINDOW_H
@- qdialogtestwindow.cpp
@#include "qdialogtestwindow.h"
#include <QtGui/QMenuBar>
#include <QtGui/QMenu>
#include <QtGui/QDialog>
#include <QtGui/QFormLayout>
#include <QtGui/QAction>
#include <QtGui/QPushButton>
#include <QtGui/QApplication>QDialogTestWindow::QDialogTestWindow(QWidget parent /= 0*/, Qt::WFlags flags /= 0/ )
: QMainWindow(parent, flags)
{}
QDialogTestWindow::~QDialogTestWindow(void)
{
MY_DELETE(m_action);
MY_DELETE(m_qDialog);
}void QDialogTestWindow::Initialize()
{
// In this case, give a parent in constructor of widget, layout or action change nothing, they can be null.
m_qDialog = MY_NEW(QDialog,AID_QT)(this);
m_qDialog->setModal(false);QFormLayout* formLayout = MY_NEW(QFormLayout,AID_QT)(this); QPushButton* pushButton = MY_NEW(QPushButton,AID_QT)(m_qDialog); pushButton->setText("Push Button"); pushButton->setDefault(true); connect(pushButton, SIGNAL(released()), this, SLOT(close())); formLayout->addRow(pushButton); m_qDialog->setLayout(formLayout); QMenuBar* menubar = MY_NEW(QMenuBar,AID_QT)(this); QMenu* menuFile = menubar->addMenu("File"); m_action = MY_NEW(QAction,AID_QT)(this); m_action->setText("QDialog"); menuFile->addAction(m_action); connect(m_action, SIGNAL(triggered()), m_qDialog, SLOT(show())); setMenuBar(menubar);
}
void QDialogTestWindow::closeEvent( QCloseEvent *e )
{
// Close the QDialog before quit the qApp, but it's doesn't affect the memory leak...
if(m_qDialog->isVisible())
m_qDialog->close();qApp->quit();
}@
My QApplication:
@#include "GUI\Qt\qdialogtestwindow.h"
// QT includes
#include <QtGui/QApplication>#include "QtApp.h"
QtApp::QtApp(const CmdLineParser& cmdline, Config& ini)
: BaseApp(cmdline, ini)
{}
QtApp::~QtApp()
{
MY_DELETE(m_testWindow);
MY_DELETE(m_app);
}int QtApp::InitApp( int argc, char** argv)
{
BaseApp::InitApp(argc, argv);m_app = MY_NEW(QApplication,AID_APP)(argc, argv); m_testWindow = MY_NEW(QDialogTestWindow,AID_APP)(); m_testWindow->Initialize(); return 0;
}
int QtApp::MainLoop()
{
m_testWindow->show();return m_app->exec();
}
void QtApp::ShutdownApp()
{
BaseApp::ShutdownApp();
}@To conclude my main
@int main(int argc, char** argv)
{
CmdLineParser cmdline = CmdLineParser(argc, argv);
Config iniFile = Config::GetInitialConfig();QtApp myApp = QtApp(cmdline, iniFile); myApp.InitApp(argc, argv); int res = myApp.MainLoop(); myApp.ShutdownApp(); return res;
}@
MY_NEW and MY_DELETE are macros for my memory manager, they call a memory allocation (or a desallocation) and log the allocation information in a map (id AID_*, allocation file, allocation line, size, etc.).
Maybe my usage of the QDialog is not appropriate, do you have any idea ? Where does the memory leak come from ? What could I do to prevent it ?
Thanks
-
Your code looks ok to me. But you wrote:
bq. My memory manager is created before the Qt initialization thanks to a static variable and shutdown after the Qt’s shutdown.I do not think that you can guarantee that your memory manager starts first and ends last, see "here":http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14.
-
Thank you for your answer.
My memory manager is initialized in the constructor of a static variable like this :
@#pragma init_seg(lib)
static MemManagerInitializer memManagerInitializer;@Thanks to the pragma directive, I am sure that this static variable is instancied before Qt's start and destroyed after Qt's shutdown. And if it is not instanciated before Qt (without the pragma), I have a lot of free call to an unreferenced memory in my memory manager from Qt.
Personnaly I think it come from the QPushButton association in a QDialog (or maybe QWidget). Do you know the executed steps when I add a QPushButton in a QDialog?
Or maybe do you have other ideas?
Thanks
-
Hi,
there are bugs in your code:
You create the form layout on the main window, add the button from the dialog and then set the layout to the dialog. Why create it on the main window?
@
QFormLayout* formLayout = MY_NEW(QFormLayout,AID_QT)(this);
@I don't know whether this has influence on your problem.
On which platform are you running? Did you try external memory testing tolls?
You can do so many things wrong in those things...
E.g. on windows, initialization of static variable (which is done before main) is not in a defined order and may only use some very special things. Otherwise the behavior is not defined. -
Hi,
thank you for your answers!
as I said in my first post, the widget parent change anything for my memory leaks but I agree this creation on the main window isn't correct. So I change my code with this, I removed all not important things to get a more basic application :
@QDialogTestWindow::~QDialogTestWindow(void)
{
MY_DELETE(m_qDialog);
}void QDialogTestWindow::Initialize()
{
// In this case, give a parent in constructor of widget, layout change nothing, they can be null.
m_qDialog = MY_NEW(QDialog,AID_QT)(this);QPushButton* pushButton = MY_NEW(QPushButton,AID_QT)(m_qDialog); //QPushButton* pushButton = MY_NEW(QPushButton,AID_QT)(this); //QPushButton* pushButton = MY_NEW(QPushButton,AID_QT)(); QMenuBar* menubar = MY_NEW(QMenuBar,AID_QT)(this); QMenu* menuFile = menubar->addMenu("File"); m_action = MY_NEW(QAction,AID_QT)(this); menuFile->addAction(m_action); connect(m_action, SIGNAL(triggered()), m_qDialog, SLOT(show())); setMenuBar(menubar); //m_action->trigger(); //m_qDialog->show();
}
void QDialogTestWindow::closeEvent( QCloseEvent *e )
{
// Close the QDialog before quit the qApp, but it's doesn't affect the memory leak...
//if(m_qDialog->isVisible())
//m_qDialog->close();
qApp->quit();
}@I run my application on windows x86, it's same thing with x64 with others memory leaks size naturally.
I didn't tried external memory testing tools.I found one thing: when I use show() of the QDialog instead use the m_action to show the QDialog, I haven't memory leaks!
It's weird because if I use close() method of the QDialog in the closeEvent() of my MainWindow
instead close manually my QDialog, I get the memory leaks... When I close manually the QDialog, I haven't the issue.An other thing, if I don't instanciate my QPushButton, whatever the parent, I haven't memory leak!
So, I will watch the destructor more in details.