繁体   English   中英

qt串口内存泄漏

[英]qt serial port memory leak

我使用以下代码与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上调试

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

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

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

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

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

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

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

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

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

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

结论:

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

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

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

对于小的“线程”任务,使用QtConcurrent要好得多。

正确的解决方法:

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

// main thread:
class Worker: public QObject {
    public:
       Worker();

    public slots:

       onInit() {
          // initialize everything
          startTimer(20);
       }

    protected:

       void timerEvent(..) {
          // do your things every 20ms
       }   
  }

  ...

  QThread * pWorkerThread = new QThread();
  pWorkerThread->setObjectName(QString("Serial"));

  Worker * pWorker = new Worker();
  Worker->setObjectName(QString("Common Storage Impl"));
  Worker->moveToThread(WorkerThread);

  connect(pWorkerThread, SIGNAL(started()), pWorker, SLOT(onInit()));
  connect(pWorkerThread, SIGNAL(finished()), pWorker, SLOT(deleteLater()));
  connect(pWorkerThread, SIGNAL(finished()), pWorkerThread, SLOT(deleteLater()));

  pWorkerThread->start();

  ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM