Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to use QNetworkAccessManager without leaking memory.

How to use QNetworkAccessManager without leaking memory.

Scheduled Pinned Locked Moved Solved General and Desktop
37 Posts 8 Posters 4.7k 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.
  • Q Offline
    Q Offline
    Q139
    wrote on last edited by Q139
    #1

    Problem is similar to discussed here: [https://forum.qt.io/topic/93081/memory-leak-on-qnetworkaccessmanager](forum link)

    Basically problem is with html requests growing memory usage, using QNetworkAccessManager.

    .h

    QNetworkAccessManager qnam;
    

    .cpp , looped part.

    
    reply = qnam.get(QNetworkRequest(url));
    
        connect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
    

    Then on QNetworkReply *reply; reply->deleteLater.

    What am i doing wrong here that causes the leak?

    So far i tested that replys deletelater wont fail.
    If problem is with memory buildup in QNetworkAccessManager...
    In the linked thread the solution is to delete QNetworkAccessManager ,but is there a way to clear individual component that grows?

    I thought maybe delete QNetworkAccessManager after every 100 requests , so it can leak for while and then recreate.
    But hopefully someone knows what is best to do.

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      What version of Qt are you using ?
      On what platform ?
      Can you provide a minimal compilable example that shows that behaviour ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      Q 1 Reply Last reply
      0
      • SGaistS SGaist

        Hi,

        What version of Qt are you using ?
        On what platform ?
        Can you provide a minimal compilable example that shows that behaviour ?

        Q Offline
        Q Offline
        Q139
        wrote on last edited by Q139
        #3

        @SGaist

        Qt Creator 4.11.1
        Based on Qt 5.14.1 (MSVC 2017, 32 bit)
        
        Built on Feb 5 2020 10:36:21
        

        Windows 10, win 7 also

        Let me know what needs to be cleaned there to avoid memory growth.
        Or if some timeout needs to be set for AcessManager

        CloseToMinimalExample

        1 Reply Last reply
        0
        • Q Offline
          Q Offline
          Q139
          wrote on last edited by Q139
          #4

          Sorry , forgot to add QApplication::processEvents(); inside while(1) loop , it may not process events at all, but with that added it grows slower
          Also no valid adress as it may behave like ddos attack.

          better .cpp file

          #include "form.h"
          #include "ui_form.h"
          #include <QtNetwork>
          #include <QUrl>
          #include "QProgressDialog"
          #include "QMessageBox"
          #include "QTextBlock"
          #include "qcoreapplication.h"
          Form::Form(QWidget *parent) :
              QWidget(parent),
              ui(new Ui::Form)
          {
              ui->setupUi(this);
          
          
          #ifndef QT_NO_SSL
              connect(&qnam, &QNetworkAccessManager::sslErrors,
                      this, &Form::sslErrors);
          #endif
          
              ui->pushButton->click();
          
          }
          
          Form::~Form()
          {
              delete ui;
          }
          
          
          bool finished=0;
          void Form::on_pushButton_clicked()
          {
          
          ui->pushButton->hide();
          
             connect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
          
          while(1){
          
              QUrl ur("test");
              startRequest(ur);
              finished=0;
          
             while(!finished){
                 QThread::msleep(1);
                 QApplication::processEvents();
             }
          
          }
          
          }
          
          
          void Form::startRequest(const QUrl &requestedUrl)
          {
              reply = qnam.get(QNetworkRequest(url));
          
          }
          
          void Form::httpFinished()
          {
              reply->deleteLater();
              finished=1;
           //  reply=NULL;
          }
          
          
          

          Is it safe to connect reply signal once and change pointers during runtime?
          Is it safe and continues to work if at some point signals&slots sees signal as nullptr in eventloop while processing signals?

          1 Reply Last reply
          0
          • Q Offline
            Q Offline
            Q139
            wrote on last edited by Q139
            #5

            Here it says i should use clearConnectionCache();

            clearAccessCache();
            clearConnectionCache();
            

            I tryed both cacheClears but it didnt help.
            If added here:

            void Form::startRequest(const QUrl &requestedUrl)
            {
                qnam.clearAccessCache();
                qnam.clearConnectionCache();
            
                reply = qnam.get(QNetworkRequest(url));
            
            }
            
            1 Reply Last reply
            0
            • Christian EhrlicherC Offline
              Christian EhrlicherC Offline
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on last edited by
              #6

              Please provide a minimal, compilable example without blocking the ui with a custom event loop.

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              Q 1 Reply Last reply
              0
              • Christian EhrlicherC Christian Ehrlicher

                Please provide a minimal, compilable example without blocking the ui with a custom event loop.

                Q Offline
                Q Offline
                Q139
                wrote on last edited by Q139
                #7

                @Christian-Ehrlicher There you go

                Christian EhrlicherC 1 Reply Last reply
                0
                • Q Q139

                  @Christian-Ehrlicher There you go

                  Christian EhrlicherC Offline
                  Christian EhrlicherC Offline
                  Christian Ehrlicher
                  Lifetime Qt Champion
                  wrote on last edited by Christian Ehrlicher
                  #8

                  @Q139 This example contains a custom local eventloop. And this loop is not stopped due to while(1) around it. This is plain wrong.
                  Then you create a new request every millisecond and don't delete it.

                  Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                  Visit the Qt Academy at https://academy.qt.io/catalog

                  Q 1 Reply Last reply
                  1
                  • Christian EhrlicherC Christian Ehrlicher

                    @Q139 This example contains a custom local eventloop. And this loop is not stopped due to while(1) around it. This is plain wrong.
                    Then you create a new request every millisecond and don't delete it.

                    Q Offline
                    Q Offline
                    Q139
                    wrote on last edited by Q139
                    #9

                    @Christian-Ehrlicher How to delete request?

                    void Form::httpFinished()
                    {
                        reply->deleteLater();
                        finished=1;
                     //  reply=NULL;
                    }
                    

                    It should catch this function via event loop every time before new request, here it sets reply for deletion.

                    Christian EhrlicherC 1 Reply Last reply
                    0
                    • Q Q139

                      @Christian-Ehrlicher How to delete request?

                      void Form::httpFinished()
                      {
                          reply->deleteLater();
                          finished=1;
                       //  reply=NULL;
                      }
                      

                      It should catch this function via event loop every time before new request, here it sets reply for deletion.

                      Christian EhrlicherC Offline
                      Christian EhrlicherC Offline
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      @Q139 Ah, the strang finished=1 does it.
                      Again: don't block, use async signals/slots.

                      Your deleteLater() is the problem since you never return to the event loop. See the documentation: "The object will be deleted when control returns to the event loop. "
                      Creating a new eventloop will not help - it's a new one, not the one where the object was created in.

                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                      Visit the Qt Academy at https://academy.qt.io/catalog

                      Q 1 Reply Last reply
                      3
                      • Christian EhrlicherC Christian Ehrlicher

                        @Q139 Ah, the strang finished=1 does it.
                        Again: don't block, use async signals/slots.

                        Your deleteLater() is the problem since you never return to the event loop. See the documentation: "The object will be deleted when control returns to the event loop. "
                        Creating a new eventloop will not help - it's a new one, not the one where the object was created in.

                        Q Offline
                        Q Offline
                        Q139
                        wrote on last edited by Q139
                        #11

                        @Christian-Ehrlicher Does QApplication::processEvents(); not go trough deleteLater()'s event loop?

                        while(!finished){
                            QThread::msleep(1);
                            QApplication::processEvents();<--
                        }
                        

                        At least it fires signals&slots events.

                        1 Reply Last reply
                        0
                        • Christian EhrlicherC Offline
                          Christian EhrlicherC Offline
                          Christian Ehrlicher
                          Lifetime Qt Champion
                          wrote on last edited by
                          #12

                          @Q139 said in How to use QNetworkAccessManager without leaking memory.:

                          At least it fires signals&slots events.

                          It executes the event loop, it does not return to it. It would be dangerous to delete objects during processEvents() since you can still be in a slot which object was deferred for deletion.

                          Again: you don't need it and it's dangerous to call processEvents() or spin a local event loop. Avoid it as much as possible.

                          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                          Visit the Qt Academy at https://academy.qt.io/catalog

                          Q 1 Reply Last reply
                          1
                          • Christian EhrlicherC Christian Ehrlicher

                            @Q139 said in How to use QNetworkAccessManager without leaking memory.:

                            At least it fires signals&slots events.

                            It executes the event loop, it does not return to it. It would be dangerous to delete objects during processEvents() since you can still be in a slot which object was deferred for deletion.

                            Again: you don't need it and it's dangerous to call processEvents() or spin a local event loop. Avoid it as much as possible.

                            Q Offline
                            Q Offline
                            Q139
                            wrote on last edited by Q139
                            #13

                            @Christian-Ehrlicher Then its solved, i tryed to bodge together networking by not returning from the while loop.
                            Assumption was that QApplication.processEvents() runs all functions of event loop including deletions.
                            It was for temprorary app i bodged together to collect data via certain api, but there is alot to get and many requests eat memory up.
                            Even bodging stuff together requires correct knowledge of how underliying functions works...

                            Is there a way to force deletion events from the while(1) event loop?

                            void Form::httpFinished()
                            {
                                disconnect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                                delete reply;
                                finished=1;
                             //  reply=NULL;
                            }
                            

                            using delete reply; still grows memory

                            JonBJ 1 Reply Last reply
                            1
                            • Q Offline
                              Q Offline
                              Q139
                              wrote on last edited by Q139
                              #14

                              Without while loop i still notice memory usage growth , what am i missing here?
                              However it jumps back in memory usage after some periods, but still goes 100+mb eventualy.

                              #include "form.h"
                              #include "ui_form.h"
                              #include <QtNetwork>
                              #include <QUrl>
                              #include "QProgressDialog"
                              #include "QMessageBox"
                              #include "QTextBlock"
                              #include "qcoreapplication.h"
                              Form::Form(QWidget *parent) :
                                  QWidget(parent),
                                  ui(new Ui::Form)
                              {
                                  ui->setupUi(this);
                              
                                  connect(this,SIGNAL(nextReq()),this,SLOT(startRequest()));//<--- to loop
                              
                              
                              #ifndef QT_NO_SSL
                                  connect(&qnam, &QNetworkAccessManager::sslErrors,
                                          this, &Form::sslErrors);
                              #endif
                              
                              }
                              
                              Form::~Form()
                              {
                                  delete ui;
                              }
                              
                              
                              bool finished=0;
                              void Form::on_pushButton_clicked()
                              {
                              
                              ui->pushButton->hide();
                              
                              
                                  QUrl ur("test");
                                  startRequest();
                              
                              
                              }
                              
                              bool once=1;
                              void Form::startRequest()
                              {
                                  QThread::msleep(1);
                                  qnam.clearAccessCache();
                                  qnam.clearConnectionCache();
                                  
                                  reply = qnam.get(QNetworkRequest(url));
                                  connect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                              
                              }
                              
                              void Form::httpFinished()
                              {
                                  disconnect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                                  reply->deleteLater();
                              
                                  emit nextReq();
                               //  reply=NULL;
                              }
                              
                              
                              
                              1 Reply Last reply
                              0
                              • Q Q139

                                @Christian-Ehrlicher Then its solved, i tryed to bodge together networking by not returning from the while loop.
                                Assumption was that QApplication.processEvents() runs all functions of event loop including deletions.
                                It was for temprorary app i bodged together to collect data via certain api, but there is alot to get and many requests eat memory up.
                                Even bodging stuff together requires correct knowledge of how underliying functions works...

                                Is there a way to force deletion events from the while(1) event loop?

                                void Form::httpFinished()
                                {
                                    disconnect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                                    delete reply;
                                    finished=1;
                                 //  reply=NULL;
                                }
                                

                                using delete reply; still grows memory

                                JonBJ Offline
                                JonBJ Offline
                                JonB
                                wrote on last edited by
                                #15

                                @Q139
                                Not knowing much about electricity, your picture above is how I power my PCs. Is there anything wrong with this setup?

                                Q 1 Reply Last reply
                                1
                                • JonBJ JonB

                                  @Q139
                                  Not knowing much about electricity, your picture above is how I power my PCs. Is there anything wrong with this setup?

                                  Q Offline
                                  Q Offline
                                  Q139
                                  wrote on last edited by Q139
                                  #16

                                  @JonB
                                  For temporary solution i think its great way to power computer/s if you really needed the power and had no access to better options.

                                  One possible bad scenario is ,if you add more PCs and increase load at some point it may act as fuse, after breaking connection short circuit and consequently breaking main fuse of the house if reasonable short circuit occurs, or just catching fire.

                                  Maybe something corrodes over the years and starts to heat, then you will get FREE house heater out of it as well in addition to powering pc, works best on wooden house.

                                  Connections using proper wires:

                                  1 Reply Last reply
                                  1
                                  • B Offline
                                    B Offline
                                    Bonnie
                                    wrote on last edited by
                                    #17

                                    I replace you sleep with timer, does this change anything?

                                    #include "form.h"
                                    #include "ui_form.h"
                                    #include <QtNetwork>
                                    #include <QUrl>
                                    #include "QProgressDialog"
                                    #include "QMessageBox"
                                    #include "QTextBlock"
                                    #include "qcoreapplication.h"
                                    Form::Form(QWidget *parent) :
                                        QWidget(parent),
                                        ui(new Ui::Form)
                                    {
                                        ui->setupUi(this);
                                    
                                    #ifndef QT_NO_SSL
                                        connect(&qnam, &QNetworkAccessManager::sslErrors,
                                                this, &Form::sslErrors);
                                    #endif
                                    
                                    }
                                    
                                    Form::~Form()
                                    {
                                        delete ui;
                                    }
                                    
                                    void Form::on_pushButton_clicked()
                                    {
                                        ui->pushButton->hide();
                                        startRequest();
                                    }
                                    
                                    void Form::startRequest()
                                    {    
                                        qnam.clearAccessCache();
                                        reply = qnam.get(QNetworkRequest(url));
                                        connect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                                    }
                                    
                                    void Form::httpFinished()
                                    {
                                        reply->deleteLater();
                                        QTimer::singleShot(1000, this, &Form::startRequest);
                                    }
                                    
                                    Q 1 Reply Last reply
                                    0
                                    • B Bonnie

                                      I replace you sleep with timer, does this change anything?

                                      #include "form.h"
                                      #include "ui_form.h"
                                      #include <QtNetwork>
                                      #include <QUrl>
                                      #include "QProgressDialog"
                                      #include "QMessageBox"
                                      #include "QTextBlock"
                                      #include "qcoreapplication.h"
                                      Form::Form(QWidget *parent) :
                                          QWidget(parent),
                                          ui(new Ui::Form)
                                      {
                                          ui->setupUi(this);
                                      
                                      #ifndef QT_NO_SSL
                                          connect(&qnam, &QNetworkAccessManager::sslErrors,
                                                  this, &Form::sslErrors);
                                      #endif
                                      
                                      }
                                      
                                      Form::~Form()
                                      {
                                          delete ui;
                                      }
                                      
                                      void Form::on_pushButton_clicked()
                                      {
                                          ui->pushButton->hide();
                                          startRequest();
                                      }
                                      
                                      void Form::startRequest()
                                      {    
                                          qnam.clearAccessCache();
                                          reply = qnam.get(QNetworkRequest(url));
                                          connect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                                      }
                                      
                                      void Form::httpFinished()
                                      {
                                          reply->deleteLater();
                                          QTimer::singleShot(1000, this, &Form::startRequest);
                                      }
                                      
                                      Q Offline
                                      Q Offline
                                      Q139
                                      wrote on last edited by Q139
                                      #18

                                      @Bonnie Unfortunately not.

                                      QNetworkAccessManager qnam;
                                      QNetworkReply *reply;
                                      
                                      void Form::startRequest()
                                      {
                                          qnam.clearAccessCache();
                                          reply = qnam.get(QNetworkRequest(QUrl("www.microsoft.com")));
                                          connect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                                      }
                                      
                                      void Form::httpFinished()
                                      {
                                           disconnect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                                          reply->deleteLater();
                                          QTimer::singleShot(1, this, &Form::startRequest);
                                      }
                                      

                                      This sums the core code up..
                                      If someone plans to use it as ddos code it will probably flood your own memory up instead.

                                      B Christian EhrlicherC 2 Replies Last reply
                                      0
                                      • Q Q139

                                        @Bonnie Unfortunately not.

                                        QNetworkAccessManager qnam;
                                        QNetworkReply *reply;
                                        
                                        void Form::startRequest()
                                        {
                                            qnam.clearAccessCache();
                                            reply = qnam.get(QNetworkRequest(QUrl("www.microsoft.com")));
                                            connect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                                        }
                                        
                                        void Form::httpFinished()
                                        {
                                             disconnect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                                            reply->deleteLater();
                                            QTimer::singleShot(1, this, &Form::startRequest);
                                        }
                                        

                                        This sums the core code up..
                                        If someone plans to use it as ddos code it will probably flood your own memory up instead.

                                        B Offline
                                        B Offline
                                        Bonnie
                                        wrote on last edited by
                                        #19

                                        @Q139 Actually, I don't get a increasing memory while testing the last and the previous code of yours.
                                        I wonder if it needs to be tested with a url that have a big size of reply data...
                                        I'm using Qt 5.12 though...

                                        Q 1 Reply Last reply
                                        0
                                        • Q Q139

                                          @Bonnie Unfortunately not.

                                          QNetworkAccessManager qnam;
                                          QNetworkReply *reply;
                                          
                                          void Form::startRequest()
                                          {
                                              qnam.clearAccessCache();
                                              reply = qnam.get(QNetworkRequest(QUrl("www.microsoft.com")));
                                              connect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                                          }
                                          
                                          void Form::httpFinished()
                                          {
                                               disconnect(reply, &QNetworkReply::finished, this, &Form::httpFinished);
                                              reply->deleteLater();
                                              QTimer::singleShot(1, this, &Form::startRequest);
                                          }
                                          

                                          This sums the core code up..
                                          If someone plans to use it as ddos code it will probably flood your own memory up instead.

                                          Christian EhrlicherC Offline
                                          Christian EhrlicherC Offline
                                          Christian Ehrlicher
                                          Lifetime Qt Champion
                                          wrote on last edited by
                                          #20

                                          @Q139 said in How to use QNetworkAccessManager without leaking memory.:

                                          If someone plans to use it as ddos code it will probably flood your own memory up instead.

                                          No it won't - there is no leak in this code anymore.
                                          The disconnect() is not needed though.

                                          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                                          Visit the Qt Academy at https://academy.qt.io/catalog

                                          Q 1 Reply Last reply
                                          0

                                          • Login

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