SASUPERNOVA
SASUPERNOVA

Reputation: 141

Memory Leak in QWebEngineView

I am trying to make a window with a QWebEngineView, and delete the QWebEngineView after the window closes. However, the QWebEngineView never seems to get deleted, and keeps running any QUrl I have loaded (e.g. a YouTube video). In my program, I have a QMainWindow with a Line Edit and a Push Button, that creates a window that loads the URL entered by the user. Here is my code:

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

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

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();
}

I have also tried using "web->close();" (which I put on the line where I have the testing artifact) in conjunction with
"web->setAttribute(Qt::WA_DeleteOnClose);" (which I put after "web = new QWebEngineView(this);"), but that didn't solve my issue either. Anyone know what I am doing wrong?

Upvotes: 1

Views: 2019

Answers (3)

Via_fx_24
Via_fx_24

Reputation: 309

Looks like something was not closed correctly.

I was using Qt 5.15 using the kit MSVC2019 32bit compiler. But Visual Studio 2017 (and not 2019) was installed on my computer. Thus, the compiler detected in Qt creator -> project -> manage kit -> compiler was the one of MSVC2017 i.e : Microsoft visual C++ compiler 15.8 (x86).

The solution is to install visual Studio 2019 and then replace Qt creator by the correct compiler (2019) i.e: Microsoft visual c++ compiler 16.7 (X86). Then I could compile without any leak of memory anymore.

Problem_With_QTWebEngine_And_MSVC_Compiler 15.8

Upvotes: 0

Venom
Venom

Reputation: 1060

You are creating QWebEngineView with parent "this" (owner) so you don't have to delete it yourself, it will be automatically deleted when it parent will. See Qt documentation about memory management :

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

it is also dangerous doing that, because if you don't create the QWebEngineView object using doWeb(QString link), you will try to delete something that doesn't exist and therefore it can lead you to undefined behavior.

remove delete web from your destructor and see if you always have the problem.

Edit : The reason why it is not destroyed : you aren't destroying SubWindow Object (the owner of QWebEngineView Object). You can Verify it yourself by printing something in the destructor. If you were destroying SubWindow object, the second time you push the button in MainWindow, your application will crashes. Since you aren't creating the SubWindow object inside your function on_push_button, but inside MainWindow::init. Your SubWindow Object is only hidden and not destroyed. It is destroyed only when you close the MainWindow. You are also Creating an instance of QWebEngineview each time you show sub (SubWindow Object), so if you show sub 3 times you will have 3 QWebEngineView inside your Subwindow.

the changes i would do to the code :

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.
}

Note that i am also not destroying subWindow object, but i m not creating QWebView each time i call the method SubWindow::doWeb(String). If it was up to me i would use a Subclassed Dialog that is not a member of MainWindow, the object would be created inside MainWindow::on_pushButton_clicked() and destroyed when i finish using it.

Upvotes: 1

SASUPERNOVA
SASUPERNOVA

Reputation: 141

OK, apparently I needed to call "web->deleteLater();" before calling "this->close();". The "delete web;" was uneeded. Still, I'd like to know why delete doesn't work in this case...

Upvotes: 1

Related Questions