当前位置:编程学习 > wap >>

内存泄露问题

大家好,最近用QT开发UI,需要创建独立的窗口,但是发现关闭新创建的窗口时存在内存泄露问题,网上找了各种方法都不好使(包括设置WA_DeleteOnClose标志,重载closeEvent并调用delete this)。
例子很简单,点击主窗口按钮出现一个新的Widget,新Widget上点击上面的close关闭。但是通过Windows内存管理器发现点击打开按钮进程内存增加,点击关闭按钮内存减少,但是增加和减少的量不一致,总是有几时KB的内存泄露问题。整个过程并没有为新的Widget设置parent,请教大家这是什么原因?(移植到ARM上也是一样的情况)

贴点儿代码好说明问题:

主窗口点击按钮通过new创建新的Widget:

void MainWindow::on_pushButton_clicked()
{
    TestWidget *test = new TestWidget();
    test->show();
}



新Widget的头文件:

#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>

class TestWidget : public QWidget
{
    Q_OBJECT
public:
    TestWidget();
    ~TestWidget();

protected slots:
    void onReturnButtonClicked();
    void closeEvent(QCloseEvent *event);
private:
    QPushButton *btn_close;
    QPushButton *btn_tmp;
    QVBoxLayout *layout;

};


新Widget的CPP文件:

#include "testwidget.h"

TestWidget::TestWidget()
{
    this->setFixedSize(480, 272);
    this->setAttribute(Qt::WA_DeleteOnClose, true);
    this->setParent(NULL);

    btn_close = new QPushButton("close");
    btn_tmp = new QPushButton("tmp");
    connect(btn_close, SIGNAL(clicked()), this, SLOT(onReturnButtonClicked()));
    layout = new QVBoxLayout();
    layout->addWidget(btn_close);
    layout->addWidget(btn_tmp);
    this->setLayout(layout);
}

void TestWidget::closeEvent(QCloseEvent *event)
{
   delete this;
}

TestWidget::~TestWidget()
{
    delete(layout);
    delete(btn_close);
    delete(btn_tmp);
}

void TestWidget::onReturnButtonClicked()
{
    this->close();
}



各位对不住,第一次来,没分,先给100分吧。 内存泄露 --------------------编程问答-------------------- 1.
TestWidget(QWidget *parent) : QWidget(parent)
{
btn_close = new QPushButton("close", this);
    btn_tmp = new QPushButton("tmp", this);
}
2.去掉this->setParent(NULL);
3.去掉
delete this;
delete(layout);
    delete(btn_close);
    delete(btn_tmp);
不需要你做无用功,Qt垃圾回收机制帮你做了,只要你的widget的父类是QObject或间接QObject
4.TestWidget *test = new TestWidget(this);

就不会有内存泄露了 --------------------编程问答-------------------- 可以保存该Widget的指针为成员变量,首次显示时创建即可。
需要弹出效果也可改用QDialog。 --------------------编程问答--------------------
引用 1 楼 LazyDreamHunter 的回复:
1.
TestWidget(QWidget *parent) : QWidget(parent)
{
btn_close = new QPushButton("close", this);
    btn_tmp = new QPushButton("tmp", this);
}
2.去掉this->setParent(NULL);
3.去掉
delete this;
delete(layout);
    delete(btn_close);
    delete(btn_tmp);
不需要你做无用功,Qt垃圾回收机制帮你做了,只要你的widget的父类是QObject或间接QObject
4.TestWidget *test = new TestWidget(this);

就不会有内存泄露了


非常感谢您的谢谢,我有几个疑问,希望和您一起探讨:
1. 按照您说的QT自动回收,前提是设置了WA_DeleteOnClose吧,也就是说下面行代码是不可少的是吗?
this->setAttribute(Qt::WA_DeleteOnClose, true);

2. 主窗口中我通过点击按钮创建新的Widget:
TestWidget *test = new TestWidget();

但是我没有办法调用delete test,一旦调用,新的Widget就消失了,那么这个new出来的TestWidget就是内存泄露了吗?还是说WA_DeleteOnClose方式会自动释放自身?
3. 从任务管理器确实看到点击打开和关闭按钮前后,进程占用的内存变少了,您知道是什么原因吗? --------------------编程问答-------------------- @LazyDreamHunter
忘记补充一点,需求中,我的主窗体MainWindow永远不会close,根据QT子窗体释放机制,那么即使为TestWidget指定了parent为MainWindow,MainWindow不关闭,TestWidget也不会释放,我的理解正确吗?
TestWidget *test = new TestWidget(this);

--------------------编程问答-------------------- 嗯,是这样子的 --------------------编程问答-------------------- 如果是这样的,

你只需要
if (pTest != NULL)
   delete pTest;
 pTest = new TestWidget();

pTest是mainwidget的成员变量,或者,函数clicked的静态变量,初始赋值= null --------------------编程问答-------------------- 其他的该指向父类的就指向父类, --------------------编程问答--------------------
引用 6 楼 LazyDreamHunter 的回复:
如果是这样的,

你只需要
if (pTest != NULL)
   delete pTest;
 pTest = new TestWidget();

pTest是mainwidget的成员变量,或者,函数clicked的静态变量,初始赋值= null


您的意思是TestWidget不设置parent,但是只创建一次。
而TestWidget中new出来的close和tmp按钮要把parent设置成TestWidget:
btn_close = new QPushButton("close", this);
btn_tmp = new QPushButton("tmp", this);

这样在TestWidget调用close的时候,这两个按钮就自动释放了是吗?
--------------------编程问答-------------------- 基本可以这木理解,

if (pTest != NULL)
   delete pTest;
 pTest = new TestWidget();

我的意思是,你如果要重复new TestWidget(),如果pTest不空的话,先删除,再new,这要就不会有必须要mainwidget退出才回收new出来的内存了。

但我觉得这样做没有必要,有1分TestWidget就行了,如果你真的要重头再来的话,只需在TestWidget,提供一个init接口,这样就不需要每次单击时,都要new了,看你怎么做了 --------------------编程问答--------------------
引用 9 楼 LazyDreamHunter 的回复:
基本可以这木理解,

if (pTest != NULL)
   delete pTest;
 pTest = new TestWidget();

我的意思是,你如果要重复new TestWidget(),如果pTest不空的话,先删除,再new,这要就不会有必须要mainwidget退出才回收new出来的内存了。

但我觉得这样做没有必要,有1分TestWidget就行了,如果你真的要重头再来的话,只需在TestWidget,提供一个init接口,这样就不需要每次单击时,都要new了,看你怎么做了


一直很迷惑这行代码:
this->setAttribute(Qt::WA_DeleteOnClose, true);

这个需要吗?只能通过它去释放TestWidget的children比如btn_close和btn_tmp,而不能主动释放test自身这个指针? --------------------编程问答-------------------- 这个可以不要 --------------------编程问答-------------------- 只要你的testWidget的孩子,父指针都指向testWidget,这个在delete testWidget的时候,testWidget会删除掉她的所有的孩子
补充:移动开发 ,  Qt
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,