简体   繁体   English

qt串口内存泄漏

[英]qt serial port memory leak

I use the following code to talk to a USB-serial port device: 我使用以下代码与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";
}

with a simple main.cpp as: 用一个简单的main.cpp作为:

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

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

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

But the memory usage keeps increasing, like 5~10MB per hour as if there are some leakage. 但内存使用量不断增加,如每小时5~10MB,好像有一些泄漏。 The device is suppose to be connected for days and weeks... 假设该设备连接数天和数周......

What am I doing wrong here? 我在这做错了什么? I am on Qt5.6 windows7 debug 我在Qt5.6 windows7上调试

Many Qt Components have an implicit dependency on its event loop. 许多Qt组件对其事件循环具有隐式依赖性。

While you are starting the main threads event loop with the call to app.exec(); 当你通过调用app.exec();启动主线程事件循环时app.exec(); you are not handling events generated by the QObjects created in the QThread MasterThread thread; 您不处理由QThread MasterThread thread;创建的QObject生成的事件MasterThread thread; . The details and nuances of Event handling in Qt are very well described on this page: https://wiki.qt.io/Threads_Events_QObjects#Threads_and_QObjects Qt中事件处理的细节和细微差别在此页面上有详细描述: https//wiki.qt.io/Threads_Events_QObjects#Threads_and_QObjects

But the solution boils down to: if you want to be able to process queued up Qt events in a thread where you are processing some long-running task you should call QCoreApplication::processEvents(); 但解决方案可归结为:如果您希望能够在处理某个长期运行任务的线程中处理排队的Qt事件,则应调用QCoreApplication::processEvents(); from time to time. 时。 This will prevent Qt events from endlessly queueing up. 这将阻止Qt事件无休止地排队。

EDITED after looking on the code Qt 5.7,5.6,5.5 and reading docs. 在查看代码Qt 5.7,5.6,5.5并阅读文档后编辑。

As an answer is already accepted, I would just add some thoughts here as it's too long for comments. 由于答案已经被接受,我只想在这里添加一些想法,因为评论太长了。

Keep things short - an answer you accepted is wrong.. 保持简短 - 你接受的答案是错误的..

There are two sides of the story. 这个故事有两个方面。 And as SO answers often taken 'as it is as long as they work' I'd like to explain myself... 因为SO答案通常是“只要它们有效”,我想解释一下......

If you look on a code provided - there is nothing wrong with it. 如果您查看提供的代码 - 它没有任何问题。 All objects are properly stack allocated and should be destroyed automatically. 所有对象都已正确堆栈分配,应自动销毁。

Point is that QtSerial uses deleteLater() and then a question - how to delete those allocations properly. 重点是QtSerial使用deleteLater()然后问题 - 如何正确删除这些分配。

If any module/object/code uses deleteLater() it requires an event loop, if deleteLater() called on a thread without event loop, object will be deleted after thread is terminated. 如果任何模块/对象/代码使用deleteLater(),它需要一个事件循环,如果在没有事件循环的线程上调用deleteLater(),则在线程终止后将删除对象。 As long as there is no event loop running for code above, processEvents will no work.. actually processEvents() is not something which is used for this, because a whole idea to return from the context which is called deleteLater() and have a next run, and that's checked in the Qt Source Code, so calling processEvent() straight after without incrementing loop count will do nothing at all, that's why answer you accepted is totally wrong. 只要没有为上面的代码运行事件循环,processEvents将无法工作..实际上processEvents()不是用于此的东西,因为从上下文返回的整个想法叫做deleteLater()并且有一个下一次运行,并在Qt源代码中检查,因此在没有递增循环计数的情况下直接调用processEvent()将完全不执行任何操作,这就是为什么你接受的答案是完全错误的。

Conclusion: 结论:

If any object requires event loop running it should be EXPLICITELY stated in the documentation as there is nothing wrong in using QIODevice in sync mode outside event loop. 如果任何对象需要运行事件循环,则应该在文档中明确说明,因为在事件循环外的同步模式下使用QIODevice没有任何问题。

So at my opinion,point is - its a bug in the QT Serial itself which I suggest you report. 所以在我看来,重点是 - 它是QT Serial本身的一个错误,我建议你报告。

In general it's really wrong practice for Qt to run never-ending loops.. It's much much better and cleaner to use QObject Worker tactic which is pushed to the thread, have proper even loop running etc. 一般来说,Qt运行永无止境的循环是非常错误的做法。使用QObject Worker策略会被推送到线程,进行正确的循环运行等等,这样做会更好更清晰。

For small 'threaded' tasks it's much better to use QtConcurrent. 对于小的“线程”任务,使用QtConcurrent要好得多。

Proper Workaround: 正确的解决方法:

you will have a thread with properly running event loop and a timer firing at 20ms to do your things 你将拥有一个正确运行事件循环的线程和一个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