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.
main.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。
我将对代码做的更改:
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
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);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
SubWindow* sub;
;
#endif
mainWindow.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 中的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章
如何将 swf 文件从内存加载到 QWebEngineView