Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for WebAssembly
  4. deleteLater() not deleting QNetworkReply
Forum Updated to NodeBB v4.3 + New Features

deleteLater() not deleting QNetworkReply

Scheduled Pinned Locked Moved Unsolved Qt for WebAssembly
3 Posts 2 Posters 85 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • F Offline
    F Offline
    Francois M
    wrote last edited by
    #1

    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"
    
    
    jsulmJ 1 Reply Last reply
    0
    • F Francois M

      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"
      
      
      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote last edited by
      #2

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

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      3
      • F Offline
        F Offline
        Francois M
        wrote last edited by
        #3

        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

        1 Reply Last reply
        1

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved