QThread内存泄漏

时间:2013-04-19 21:20:20

标签: c++ qt qt5

main.cpp中:

#include <QCoreApplication>
#include <QtCore>
#include "myobject.h"

QThread* cThread;
MyObject* cObject;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    cThread = new QThread();
    cObject = new MyObject();
    cObject->moveToThread(cThread);

    QObject::connect(cThread, SIGNAL(started()),
                     cObject, SLOT(doWork()));

    QObject::connect(cThread, SIGNAL(finished()),
                     cThread, SLOT(deleteLater()));

    QObject::connect(cThread, SIGNAL(finished()),
                     cObject, SLOT(deleteLater()));

    cThread->start();

    return a.exec();
}

myobject.cpp:

#include "myobject.h"

MyObject::MyObject(QObject *parent) :
    QObject(parent)
{
}

void MyObject::doWork()
{
    qDebug() << "Hi";
    QThread::currentThread()->quit();
    return;
}

myobject.h:

#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <QtCore>

class MyObject : public QObject
{
    Q_OBJECT
public:
    explicit MyObject(QObject *parent = 0);

signals:

public slots:
    void doWork();

};

#endif // MYOBJECT_H

显然,根据:https://stackoverflow.com/a/16062717,存在内存泄漏,但我该如何解决?我想我必须返回事件循环然后调用退出?但问题是我无法访问事件循环。

3 个答案:

答案 0 :(得分:1)

没有内存泄漏。如果你坚持object modelobject trees and ownership,Qt会正确清理。我也喜欢关注documented examples

以下是您引用的示例,deleteLater()上添加了观察结果。

的main.cpp

#include <QCoreApplication>
#include <QtCore>
#include <QThread>

class MyThread : public QThread
{
    Q_OBJECT
public slots:
    void deleteLater()
    {
        qDebug() << Q_FUNC_INFO;
        QThread::deleteLater();
    }
};


class MyObject : public QObject
{
    Q_OBJECT
public:
    explicit MyObject(QObject *parent = 0){}

signals:

public slots:
    void deleteLater()
    {
        qDebug() << Q_FUNC_INFO;
        QObject::deleteLater();
    }

    void doWork()
    {
        qDebug() << "Hi";
        QThread::currentThread()->quit(); // It is supposed to stop here, but it doesn't.
        return;
        for (int i = 0; i < 1000000; i++) {
            qDebug() << i;
        }
    }

};

QThread* cThread;
MyObject* cObject;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    cThread = new MyThread();
    cObject = new MyObject();
    cObject->moveToThread(cThread);

    QObject::connect(cThread, SIGNAL(started()),
                     cObject, SLOT(doWork()));

    QObject::connect(cThread, SIGNAL(finished()),
                     cThread, SLOT(deleteLater()));

    QObject::connect(cThread, SIGNAL(finished()),
                     cObject, SLOT(deleteLater()));

    cThread->start();

    return a.exec();
}

输出:

Hi
void __thiscall MyObject::deleteLater(void)
void __thiscall MyThread::deleteLater(void)

希望有所帮助。

答案 1 :(得分:0)

根据standard This function does nothing if the thread does not have an event loop.,您在(第二个)主题中没有事件循环。尝试调试代码?

试试这个:

的main.cpp

#include <QCoreApplication>
#include <QtCore>
// #include "myobject.h"

// QThread* cThread;
// MyObject* cObject;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
//     cThread = new QThread();
//     cObject = new MyObject();
//     cObject->moveToThread(cThread);

//     QObject::connect(cThread, SIGNAL(started()),
//                      cObject, SLOT(doWork()));

//     QObject::connect(cThread, SIGNAL(finished()),
//                      cThread, SLOT(deleteLater()));

//     QObject::connect(cThread, SIGNAL(finished()),
//                      cObject, SLOT(deleteLater()));

//     cThread->start();

    return a.exec();
}

并查看是否会返回。

没有内存泄漏,因为你的doWork返回正常,删除是由a.exec()内的main-loop-event完成的。但是a.exec()永远不会返回。你必须通过QCoreApplication::quit();终止你的申请(但不是在线程中,因为你终止整个应用程序)。

您可以在tutorial

中阅读

答案 2 :(得分:0)

我是链接上的海报。事实上,默认连接没有内存泄漏。通过继承deleteLater和析构函数(如@phyatt),您获得了:

Hi 
void MyObject::deleteLater() 
virtual MyObject::~MyObject()  Being deleted 
void MyThread::deleteLater() 
virtual MyThread::~MyThread()  Being deleted 

但是如果您在连接中使用Qt::QueueConnection,则获得:

Hi 
void MyThread::deleteLater() 
virtual MyThread::~MyThread()  Being deleted 

对象cObject被泄露了。

当线程 有效地 退出时,它没有记录。所以我不能争论这种行为是否总是一样的。一种可能性是使线程启动器负责执行清理工作。例如:

 void cleanup(){
  cThread->exit();
  cThread->wait();
  delete cThread;
  delete cObject;
 }

要完成整理,您无需使用此代码修复任何内容。