簡體   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