QWebEngineView 中的内存泄漏

Posted

技术标签:

【中文标题】QWebEngineView 中的内存泄漏【英文标题】:Memory Leak in QWebEngineView 【发布时间】:2017-02-26 01:09:50 【问题描述】:

我正在尝试使用 QWebEngineView 创建一个窗口,并在窗口关闭后删除 QWebEngineView。但是,QWebEngineView 似乎永远不会被删除,并且会继续运行我加载的任何 QUrl(例如 YouTube 视频)。在我的程序中,我有一个带有 Line Edit 和 Push Button 的 QMainWindow,它创建了一个加载用户输入的 URL 的窗口。这是我的代码:

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "subwindow.h"


namespace Ui

class MainWindow;


class MainWindow : public QMainWindow

    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    void init();
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    SubWindow *sub;

;

#endif // MAINWINDOW_H

子窗口.h

#ifndef SUBWINDOW_H
#define SUBWINDOW_H

#include <QMainWindow>

#include <QtWebEngineWidgets/qwebengineview.h>
#include <QTimer>

namespace Ui

class SubWindow;


class SubWindow : public QMainWindow

    Q_OBJECT

public:
    explicit SubWindow(QWidget *parent = 0);
    void doWeb(QString link);
    ~SubWindow();

private:
    Ui::SubWindow *ui;
    QWebEngineView *web;

private slots:
    void on_pushButton_clicked();

;

#endif // SUBWINDOW_H

MainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)

    ui->setupUi(this);


void MainWindow::init()

    this->showMaximized();

    sub = new SubWindow(this);


MainWindow::~MainWindow()

    delete ui;


void MainWindow::on_pushButton_clicked()

    sub->doWeb(ui->lineEdit->text());

SubWindow.cpp

#include "subwindow.h"
#include "ui_subwindow.h"

SubWindow::SubWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::SubWindow)

    ui->setupUi(this);


void SubWindow::doWeb(QString link)

    this->show();
    web = new QWebEngineView(this);

    ui->verticalLayout->addWidget(web);

    web->load(QUrl(link, QUrl::TolerantMode));
    web->show();


SubWindow::~SubWindow()

    delete web; //Doesn't seem to work, since memory is still allocated in task manager
    delete ui;


void SubWindow::on_pushButton_clicked()

    this->close(); //Artifact for testing purposes.

ma​​in.cpp

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

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    MainWindow w;
    w.init();

    return a.exec();

我也尝试过使用“web->close();” (我把它放在我有测试工件的地方)与 “web->setAttribute(Qt::WA_DeleteOnClose);” (我把它放在“web = new QWebEngineView(this);”之后),但这也没有解决我的问题。有谁知道我做错了什么?

【问题讨论】:

你怎么知道QWebEngine没有被销毁? 首先,我使用任务管理器,注意到在我按下 MainWindow Push Button 之前,程序使用了大约 55MB 的 RAM。在我按下它之后,它变成了大约 144MB,在关闭子窗口后仍然保持分配。除此之外,当我加载 YouTube 视频时,我仍然可以听到关闭窗口后播放的声音。 【参考方案1】:

您正在使用父级“this”(所有者)创建 QWebEngineView,因此您不必自己删除它,它会在父级删除时自动删除。请参阅有关内存管理的 Qt 文档:

http://doc.qt.io/qt-5/objecttrees.html

这样做也很危险,因为如果您不使用 doWeb(QString link) 创建 QWebEngineView 对象,您将尝试删除不存在的内容,因此可能会导致您出现未定义的行为。

从你的析构函数中删除delete web,看看你是否总是有问题。

编辑: 它没有被破坏的原因:你没有破坏 SubWindow 对象(QWebEngineView 对象的所有者)。您可以通过在析构函数中打印一些内容来自己验证它。 如果您正在销毁 SubWindow 对象,则第二次按下 MainWindow 中的按钮时,您的应用程序将崩溃。由于您不是在函数 on_push_button 内创建 SubWindow 对象,而是在 MainWindow::init 内创建。您的 SubWindow 对象只是隐藏而不被破坏。只有当您关闭 MainWindow 时它才会被销毁。每次显示 sub(SubWindow 对象)时,您还创建了一个 QWebEngineview 实例,因此如果显示 sub 3 次,您的子窗口中将有 3 个 QWebEngineView。

我将对代码做的更改:

ma​​in.cpp

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

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();

ma​​inWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "subwindow.h"

namespace Ui

class MainWindow;


class MainWindow : public QMainWindow

    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    SubWindow* sub;
;
#endif

ma​​inWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow), sub(new SubWindow(this))

    ui->setupUi(this);

MainWindow::~MainWindow()

    delete ui;

void MainWindow::on_pushButton_clicked()

    sub->show();
    sub->doWeb(ui->lineEdit->text());

subWindow.h

#ifndef SUBWINDOW_H
#define SUBWINDOW_H

#include <QMainWindow>

#include <QtWebEngineWidgets/qwebengineview.h>
#include <QTimer>

namespace Ui

class SubWindow;


class SubWindow : public QMainWindow

    Q_OBJECT

public:
    explicit SubWindow(QWidget *parent = 0);
    void doWeb(QString link);
    ~SubWindow();

private:
    Ui::SubWindow *ui;
    QWebEngineView *web;

private slots:
    void on_pushButton_clicked();

;

#endif // SUBWINDOW_H

subWindow.cpp

#include "subwindow.h"
#include "ui_subwindow.h"

SubWindow::SubWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::SubWindow),
    web(new QWebEngineView(this))

    ui->setupUi(this);
    ui->verticalLayout->addWidget(web);

void SubWindow::doWeb(QString link)

    web->load(QUrl(link, QUrl::TolerantMode));

SubWindow::~SubWindow()

    delete ui;

void SubWindow::on_pushButton_clicked()

    this->close(); //Artifact for testing purposes.

请注意,我也不会破坏 subWindow 对象,但我不会在每次调用方法 SubWindow::doWeb(String) 时创建 QWebView。 如果由我决定,我将使用不是 MainWindow 成员的子类对话框,该对象将在 MainWindow::on_pushButton_clicked() 内创建,并在我完成使用后销毁。

【讨论】:

感谢您的回答!我知道使用“this”会使对象在其父对象之前被删除,但是,看到我的 WebEngineView 从未被删除,我在析构函数中添加了“delete web”以查看它是否可以工作。显然,这失败了,所以我尝试了“web->deleteLater();”,结果出乎意料地奏效了。不过我还是不明白为什么会这样。 我找到了泄漏的原因。我编辑了我的答案。 您的代码不能完全正常工作,因为 SubWindow 永远无法访问所请求的网站,因为您从未创建 QWebView。但是,如果我只添加“this->setAttribute(Qt::WA_DeleteOnClose, true);”在 SubWindow 的构造函数中,无需对我的原始代码进行任何更改,泄漏就消失了,从而证明了您的观点,即我永远不会破坏我的 SubWindow。哇,我觉得很傻!至于你提到的崩溃,我通过移动“sub = new SubWindow(this);”解决了它在“void MainWindow::on_pushButton_clicked()”中,就在调用 doWeb() 之前。谢谢!你是最有帮助的! 我在 SubWindow 构造函数中创建了 QWebViewEngine。代码工作我测试了它。 确实,我没有注意到您实际上创建了它。奇怪的是,当我使用它时,按钮并没有响应我点击它。无论如何,再次感谢您的帮助!【参考方案2】:

好的,显然我需要调用“web->deleteLater();”打电话之前 “这->关闭();”。 “删除网络”;是不需要的。不过,我想知道为什么在这种情况下删除不起作用...

【讨论】:

【参考方案3】:

似乎有些东西没有正确关闭。

我在使用套件 MSVC2019 32 位编译器时使用 Qt 5.15。但是我的电脑上安装了 Visual Studio 2017(而不是 2019)。因此,在 Qt creator -> project -> manage kit -> compiler 中检测到的编译器是 MSVC2017 之一,即:Microsoft Visual C++ compiler 15.8 (x86)。

解决方案是安装 Visual Studio 2019,然后用正确的编译器 (2019) 替换 Qt creator,即:Microsoft visual c++ compiler 16.7 (X86)。 然后我就可以编译而没有任何内存泄漏了。

【讨论】:

以上是关于QWebEngineView 中的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

C语言中的指针和内存泄漏

转C 语言中的指针和内存泄漏

如何将 swf 文件从内存加载到 QWebEngineView

闭包中的 内存泄漏

IOS性能调优系列:使用Instruments动态分析内存泄漏

IOS性能调优系列:使用Instruments动态分析内存泄漏