qt串口内存泄漏

时间:2016-07-05 10:11:42

标签: c++ qt

我使用以下代码与USB串口设备通信:

#include "masterthread.h"
#include <QtSerialPort/QSerialPort>
#include <QTime>
#include "Windows.h"
#include "Psapi.h"
#include <QDebug>
QT_USE_NAMESPACE

MasterThread::MasterThread(QObject *parent)
: QThread(parent), waitTimeout(0), quit(false)
{
}

MasterThread::~MasterThread()
{
    mutex.lock();
    quit = true;
    cond.wakeOne();
    mutex.unlock();
    wait();
}

void MasterThread::run()
{
    bool currentPortNameChanged = false;

    QSerialPort serial;
    serial.setPortName("COM3");
    serial.setBaudRate(57600);
    serial.setStopBits(static_cast<QSerialPort::StopBits>(1));
    serial.setDataBits(static_cast<QSerialPort::DataBits>(8));
    serial.setParity(static_cast<QSerialPort::Parity>(0));
    serial.open(QIODevice::ReadWrite);

    //Tell the serial port connected device to start talking
    //--------------------------------------
    const char init[] = { 0x0d, 0x0d, 0x0d };
    serial.write(init, sizeof(init));
    const char* cmd = "mavlink stop\n";
    serial.write(cmd, strlen(cmd));
    serial.write(init, 2);
    cmd = "uorb start";
    serial.write(cmd, strlen(cmd));
    serial.write(init, 2);
    cmd = "sh /etc/init.d/rc.usb\n";
    serial.write(cmd, strlen(cmd));
    serial.write(init, 4);
    serial.waitForBytesWritten(100);

    int i = 0;
    int j = 0;
    forever
    {

        //Write test data out
        //-----------------------------
        QByteArray test(2000, 't');
        serial.write(test);
        bool check = serial.waitForBytesWritten(100);
        if (!check)
        {
            qDebug() << "FAIL: " << j++;
        }

        if (serial.waitForReadyRead(20))
        {
            QByteArray responseData = serial.readAll();
            while (serial.waitForReadyRead(10))
                responseData += serial.readAll();

            QString response(responseData);
            qDebug() << response;
        }
        QThread::msleep(20);

        //Print memory usage
        //---------------------------------------------------
        if (i++ % 10 == 0)
        {
            PROCESS_MEMORY_COUNTERS memcount;
            if (!GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) return;
            qDebug()<<"----------------------------" << memcount.WorkingSetSize / 1024 << "KB memory used";
        }
    } // end foever

    qDebug() << "Exiting forever loop";
}

使用简单的main.cpp:

#include <QApplication>
#include "masterthread.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    MasterThread thread;
    thread.start();
    return app.exec();
}

但内存使用量不断增加,如每小时5~10MB,好像有一些泄漏。 假设设备连接数天和数周......

我在这里做错了什么?我在Qt5.6 windows7 debug

2 个答案:

答案 0 :(得分:2)

许多Qt组件对其事件循环具有隐式依赖。

当您通过调用app.exec();启动主线程事件循环时,您不处理由QThread MasterThread thread;中创建的QObject生成的事件。 Qt中事件处理的细节和细微差别在此页面上有详细描述:https://wiki.qt.io/Threads_Events_QObjects#Threads_and_QObjects

但解决方案可归结为:如果您希望能够在处理长期运行任务的线程中处理排队的Qt事件,则应不时调用QCoreApplication::processEvents();。这将阻止Qt事件无休止地排队。

答案 1 :(得分:0)

在查看代码Qt 5.7,5.6,5.5并阅读文档后编辑。

由于答案已经被接受,我只想在这里添加一些想法,因为评论太长了。

保持简短 - 你接受的答案是错误的..

故事有两个方面。因为SO答案通常是“只要它们有效”,我想解释一下......

如果您查看提供的代码 - 它没有任何问题。所有对象都已正确堆栈分配,应自动销毁。

重点是QtSerial使用deleteLater()然后问题 - 如何正确删除这些分配。

如果任何模块/对象/代码使用deleteLater(),它需要一个事件循环,如果在没有事件循环的线程上调用deleteLater(),则在线程终止后将删除对象。只要没有为上面的代码运行事件循环,processEvents将无法工作..实际上processEvents()不是用于此的东西,因为从上下文返回的整个想法叫做deleteLater()并且有一个 next 运行,并在Qt源代码中检查,因此在不增加循环计数的情况下直接调用processEvent()将不会执行任何操作,这就是为什么您接受的答案是完全错误的。

结论:

如果任何对象需要运行事件循环,则应该在文档中明确说明,因为在事件循环外的同步模式下使用QIODevice没有任何问题。

所以在我看来,重点是 - 它是QT Serial本身的一个错误,我建议你报告。

一般来说,Qt运行永无止境的循环真是错误的做法。 使用推送到线程的QObject Worker策略,使用正确的循环运行等更好更清晰。

对于小型“线程”任务,使用QtConcurrent会更好。

正确的解决方法:

你将拥有一个正确运行事件循环的线程和一个20ms的计时器来执行你的工作

undefined