deleteLater() not deleting QNetworkReply
-
Hi,
I've built a small application to test Qt's network stack on WebAssembly.
The data I’m loading is quite large (around 20 MB), and after a few GET requests I quickly run out of memory, even though I don’t do anything with the downloaded data.To investigate, I added a debug trace inside the QNetworkReply destructor in the Qt sources, and I noticed that the destructor is never called on WebAssembly.
On the other hand, when running the exact same code on Qt for Windows (non-WASM), the QNetworkReply destructor is called immediately after replyFinished().So my question is:
Why is deleteLater() never deleting the object in WebAssembly?
Does this have something to do with the event loop not running (since exec() is not used)?
And if it does how can I delete my QNetworkReply?Thanks in advance.
Here is the code :
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QObject> #include <QNetworkAccessManager> #include <QNetworkRequest> #include <QNetworkReply> #include <QDebug> #include <QThread> #include <cstdio> #include <iostream> #include <math.h> #include <chrono> #include <thread> #include <emscripten.h> #include <emscripten/heap.h> #include <sanitizer/lsan_interface.h> using namespace std; void printMemoryUsage() { size_t current = emscripten_get_heap_size(); size_t max = emscripten_get_heap_max(); printf("Heap total: %.2f MB\n", max / (1024.0 * 1024.0)); printf("Heap used: %.2f MB\n", current / (1024.0 * 1024.0)); } class ButtonHandler : public QObject { Q_OBJECT public: ButtonHandler(QObject* parent = nullptr) : QObject(parent) { m_network_manager = new QNetworkAccessManager(this); connect(m_network_manager, &QNetworkAccessManager::finished, this, &ButtonHandler::replyFinished); } public slots: void replyFinished(QNetworkReply* a_reply) { if (a_reply->error() == QNetworkReply::NoError) { QByteArray data = a_reply->readAll(); qDebug() << "Success! Size:" << (data.size() / 1024.0 / 1024.0) << "MB"; } else { qDebug() << "Error:" << a_reply->errorString(); } a_reply->deleteLater(); printMemoryUsage(); } void onButtonClicked() { printMemoryUsage(); m_network_manager->get(QNetworkRequest(QUrl("https://127.0.0.1:8443/api/v1/patients/1/image/3D/20"))); } private: QNetworkAccessManager* m_network_manager{nullptr}; }; QGuiApplication* g_app = nullptr; QQmlApplicationEngine* g_engine = nullptr; ButtonHandler* g_handler = nullptr; int main(int argc, char* argv[]) { g_app = new QGuiApplication(argc, argv); g_engine = new QQmlApplicationEngine(); g_handler = new ButtonHandler(g_app); g_engine->rootContext()->setContextProperty("buttonHandler", g_handler); g_engine->loadFromModule("vtkqml", "Main"); return 0; } #include "main.moc" -
Hi,
I've built a small application to test Qt's network stack on WebAssembly.
The data I’m loading is quite large (around 20 MB), and after a few GET requests I quickly run out of memory, even though I don’t do anything with the downloaded data.To investigate, I added a debug trace inside the QNetworkReply destructor in the Qt sources, and I noticed that the destructor is never called on WebAssembly.
On the other hand, when running the exact same code on Qt for Windows (non-WASM), the QNetworkReply destructor is called immediately after replyFinished().So my question is:
Why is deleteLater() never deleting the object in WebAssembly?
Does this have something to do with the event loop not running (since exec() is not used)?
And if it does how can I delete my QNetworkReply?Thanks in advance.
Here is the code :
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QObject> #include <QNetworkAccessManager> #include <QNetworkRequest> #include <QNetworkReply> #include <QDebug> #include <QThread> #include <cstdio> #include <iostream> #include <math.h> #include <chrono> #include <thread> #include <emscripten.h> #include <emscripten/heap.h> #include <sanitizer/lsan_interface.h> using namespace std; void printMemoryUsage() { size_t current = emscripten_get_heap_size(); size_t max = emscripten_get_heap_max(); printf("Heap total: %.2f MB\n", max / (1024.0 * 1024.0)); printf("Heap used: %.2f MB\n", current / (1024.0 * 1024.0)); } class ButtonHandler : public QObject { Q_OBJECT public: ButtonHandler(QObject* parent = nullptr) : QObject(parent) { m_network_manager = new QNetworkAccessManager(this); connect(m_network_manager, &QNetworkAccessManager::finished, this, &ButtonHandler::replyFinished); } public slots: void replyFinished(QNetworkReply* a_reply) { if (a_reply->error() == QNetworkReply::NoError) { QByteArray data = a_reply->readAll(); qDebug() << "Success! Size:" << (data.size() / 1024.0 / 1024.0) << "MB"; } else { qDebug() << "Error:" << a_reply->errorString(); } a_reply->deleteLater(); printMemoryUsage(); } void onButtonClicked() { printMemoryUsage(); m_network_manager->get(QNetworkRequest(QUrl("https://127.0.0.1:8443/api/v1/patients/1/image/3D/20"))); } private: QNetworkAccessManager* m_network_manager{nullptr}; }; QGuiApplication* g_app = nullptr; QQmlApplicationEngine* g_engine = nullptr; ButtonHandler* g_handler = nullptr; int main(int argc, char* argv[]) { g_app = new QGuiApplication(argc, argv); g_engine = new QQmlApplicationEngine(); g_handler = new ButtonHandler(g_app); g_engine->rootContext()->setContextProperty("buttonHandler", g_handler); g_engine->loadFromModule("vtkqml", "Main"); return 0; } #include "main.moc"@Francois-M See https://doc.qt.io/qt-6/qobject.html#deleteLater
"In situations where Qt is not driving the event dispatcher via e.g. QCoreApplication::exec() or QEventLoop::exec(), deferred deletes will not be processed automatically.". You will also find a work-around there. -
The aboutToBlock signal is not launch in wasm because the thread is always running, but the line :
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
Indeed call the delete from the deleteLater()Thank you for the help