[英]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.