QLabel 线程内存泄漏

问题描述 投票:0回答:1

我发现 Qt 和 QLabel 存在内存泄漏问题。

当启动 QThread 并从中发出信号以更新 GUI 并更改信号中 QLabel 的文本时,可以注意到(使用 Windows 任务管理器)RAM 快速增加。

测试此代码的代码非常简单,是从应用程序中提取的,在该应用程序中,我从同一线程并使用相同的信号更改不同项目的文本,唯一导致问题的是 QLabel。

如果我不是从线程更改文本,而是从主窗口中的 while 循环更改文本,则不会出现问题。

我强调,我从同一线程更改多个对象的文本,没有任何内存泄漏,并且应用程序保持稳定。下班后使用 QLabel,应用程序达到 2GB 并且变得难以管理。

我在主窗口用户界面中添加了一个启动线程的按钮和标签。全局 g_MainFormUnit 是对表单的引用。我在我的代码中使用了这种技术,这不会在其他地方造成任何问题。
该代码是使用 Qt 6.4.2 MinGW 64 位调试针对 Windows 编译的。

这是我的代码。

主窗口.cpp

#include <QThread>
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "spydriver_thread.h"
#include "shared.h"

    Ui::MainWindow      * g_MainFormUnit;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    g_MainFormUnit = ui;
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_StartThreadButton_clicked()
{
    // Capture Thread to fill packets
    SpyDriver_ShowViewThread * workerThread = new SpyDriver_ShowViewThread ();
    workerThread->start();
    QObject::connect(workerThread, &SpyDriver_ShowViewThread::InsertPacket, workerThread, &SpyDriver_ShowViewThread::on_InsertPacket);

}

spydriver_thread.cpp

#include <QtCore>

// Includes
#include <stdio.h>
#include <string.h>

// Qt Includes
#include <QtGlobal>
#include <QThread>
#include <QCoreApplication>
#include <QtConcurrent/QtConcurrent>

#include "spydriver_thread.h"
#include "shared.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"

void SpyDriver_ShowViewThread::on_InsertPacket                (int in_Packet)
{
    char PacketCounterText [16];
    memset (PacketCounterText, 0, sizeof(PacketCounterText));
    sprintf (PacketCounterText, "[%05d]", in_Packet);

    g_MainFormUnit->SessionPacketNumberLabel->setText(QString(PacketCounterText));  // **This causes the memory leak**

    return;
}

// --- CONSTRUCTOR ---
SpyDriver_ShowViewThread::SpyDriver_ShowViewThread()
{
    return;
}

// --- DECONSTRUCTOR ---
SpyDriver_ShowViewThread::~SpyDriver_ShowViewThread()
{
    // free resources
    return;
}

主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_StartThreadButton_clicked();

private:
    Ui::MainWindow *ui;

};


#endif // MAINWINDOW_H

spydriver_thread.h

#ifndef __MULTISERIAL_SPYDRIVER_THREAD_H__
#define __MULTISERIAL_SPYDRIVER_THREAD_H__

#include <QtCore>

// Qt Includes
#include <QtGlobal>
#include <QThread>
#include <QCoreApplication>
#include <QtConcurrent/QtConcurrent>

#include <stdio.h>


class SpyDriver_ShowViewThread : public QThread
{
    Q_OBJECT

    void run() override {
        int i = 0;
        while (1)
        {
            emit InsertPacket (i);
            i++;
        }
    }

public:
    SpyDriver_ShowViewThread();
    ~SpyDriver_ShowViewThread();

public slots:

    void on_InsertPacket                 (int in_Packet);

signals:

    void InsertPacket                (int in_Packet);

private:

};

#endif

共享.h

#ifndef SHARED_H
#define SHARED_H

#include    "mainwindow.h"

    extern Ui::MainWindow      * g_MainFormUnit;

#endif // SHARED_H
c++ qt
1个回答
0
投票

您的线程发出信号的速度比 GUI 线程处理信号的速度快。他们排队,并且队列大小不断增长。

确实有道理,GUI 线程也在做很多其他事情,例如更新屏幕和处理操作系统事件。您的工作线程 OTOH 除了添加为 GUI 线程事件循环发出的排队信号外什么也没做。

向工作线程添加一个微小的睡眠,或者在信号发出和接收槽之间添加一个信号量,以限制排队信号的数量。


一般的解决方案是添加一个单独的信号处理步骤,要么在发出线程中,要么在另一个线程中(或者可能在 GUI 线程中)。中间步骤应跟踪 UI 应显示的值,但仅以较长的时间间隔更新 UI。对于任何非实时、非游戏类应用程序来说,100 毫秒的间隔可能就足够了。

© www.soinside.com 2019 - 2024. All rights reserved.