Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Memory Leak issue due to dynamic creation of a QNetworkAccessManager object, locally inside a member function.



  • Hi All,

    How do we deal with memory leaks due to creation of a dymanic object locally inside a member function:

    Consider the scenario:

    I am working on client server application, where client application sends url requests to server and fetches information.

    @void MyClientApp::sendRequestToServer()
    {
    QNetworkAccessManager qnam;
    /
    Form the URL String */
    QString myurl ="http://" + this->server_address+":"+HTTP_PORT + get_country_list + "&CMSADDRESS=" + cmsIPAddress;
    qnam = new QNetworkAccessManager(this);

    QObject::connect(qnam, SIGNAL(finished(QNetworkReply*)),this,SLOT(handleServerResponse(QNetworkReply*)));
    return;

    }

    @
    In the above code object qnam is created dynamically, since the object created locally gets destroyed when the request method returns and the qnam cannot emit signal when the request returns coz it will out of scope.

    I create many such requests in my application and each creates the QNetworkAccessManager Object dynamically, but I do not delete the object since there is a signal/slot mechanism.

    Is there any way to balance memory leaks and yet not compromise on signal/slot functionality?


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Why are you creating a new QNAM each time you want to send a request ? You can create it once and use it multiple times, it would be cleaner.



  • Hi Gaist,

    Thanks for ur reply. You mean to say I create a member variable and use it.
    If I create a member variable, then I need to call delete each time, before allocating dynamic memory again in a new request.
    The only place where I can delete the QNAM is when I get a reply from the server and finish processing the response, in my case in slot handleServerResponse(). Am I thinking on the correct lines? or the other way is hold to hold each QNAM in a QList and delete the whole container when application is destroyed.

    Thanks,
    Jeevan


  • Lifetime Qt Champion

    No, I meant to say: create only one QNAM and keep it.

    You didn't answer my question: why are you creating a QNAM for each request ? QNAM can handle several requests without any problem



  • I tried using a single QNAM to handle multiple requests but the Application always logs an error. My applications always throws up an error in the slot function dealing with processing QNetworkReply for the second request.

    Infact the QXmlStreamReader indicates an error when processing the network reply of second request.

    @QByteArray contents=reply->readAll();
    QXmlStreamReader reader(contents);
    if (reader.hasError())
    {
    qDebug() << "reader returned error";
    }@

    In my case QNam is successfull while dealing with single request but while sending multiple requests, it is failing miserably.

    The XMLReader is always indicating that the reply content has some error.



  • Can you do something like:

    qnam->deleteLater();

    ?



  • You wrote: "In the above code object qnam is created dynamically, since the object created locally gets destroyed when the request method returns".

    I don't think that this is the case.


  • Lifetime Qt Champion

    .@ vidar, it is, an object created on the stack will be destroyed once it's out of scope.

    .@ jeevan_reddy Can you show the complete code of sendRequestToServer and handleServerResponse ?



  • but qnam is created on the heap, on his example



  • ... I mean, that's the reason for the memory leap. ;) Or let's say, the object that qnam points to is still alive after the method is left. So I don't really see a reason for why the signal emit should fail. The only reason could be a badly written connect function. ;)



  • However, maybe I just got the description wrong.
    I suggest a pool of QNetworkAccessManager objects.



  • vldar: I really think you haven't got the problem I am facing here.

    the issus is that If I create QNetworkAccessManager object dynamically, I have a memory leak to deal with.
    If i create the object locally on the stack then I risk the failure of signal/slot mechanism, since the qnam object gets deleted once the method returns.



  • SGaist : Please find the sample code below uses only one QNetworkAccessManager object to handle multiple requests

    @
    MyClientApplication::MyClientApplication()
    {
    qnam = new QNetworkAccessManager() ;
    }
    void MyClientApplication::sendRequestConfigurationDetails()
    {
    /* Create a one-time execute timer to check connectivity with server */
    download_started_flag = false;

    /* Form the URL String */
    QString myurl ="http://" + this->usr->server_address+":"+HTTP_PORT + "/serverrequest/cms.cgi?ACTION=getConfigDetails";
    
        QObject::connect(qnam, SIGNAL(finished(QNetworkReply*)),this,
                                SLOT(handleServerResponse(QNetworkReply*)));
    QUrl url = myurl;
    this->timeoutTimer->start();
    reply = qnam->get(QNetworkRequest(url));
    connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(downloadStatus(qint64)));
    return;
    

    }

    void MyClientApplication::handleServerResponse(QNetworkReply* reply)
    {
    MMCommonError *com_class = new MMCommonError();
    if ( this->timeoutTimer && this->timeoutTimer->isActive())
    {
    this->timeoutTimer->stop();
    }
    // error received?
    if (reply->error() != QNetworkReply::NoError)
    {
    com_class->ShowError(HTTP_COMMUNICATION_ERROR);
    reply->deleteLater();
    this->setCursor(Qt::ArrowCursor);
    return;
    }

    QByteArray contents=reply->readAll();
    QXmlStreamReader reader(contents);
    QString err;
    int errcode=0;
    while (!reader.atEnd())
    {
    reader.readNext();
    if (reader.isStartElement())
    {
    if (reader.name() == "status")
    {
    /* It may be OK or error code */
    err = reader.readElementText();
    if (err.compare("OK") == 0) {
    errcode = 0;
    } else {
    errcode = err.toInt();
    break;
    }
    continue;
    }

          if (reader.name() == "ServerAddress")
          {
     /*do smethg */
    

    continue;
    }
    if(reader.name() == "CustomerID")
    {
    /*do smethg */
    continue;
    }
    if(reader.name() == "Country")
    {
    QString country = reader.readElementText();
    if (!country.isEmpty())
    {
    ui->countryComboBox->setEnabled(true);
    ui->countryComboBox->clear();
    ui->countryComboBox->insertItem(0,country);
    this->currentCountry = country;
    }
    continue;
    }
    if(reader.name() == "City")
    {
    QString city = reader.readElementText();
    if (!city.isEmpty())
    {
    ui->cityComboBox->setEnabled(true);
    ui->cityComboBox->clear();
    ui->cityComboBox->insertItem(0,city);
    this->currentCity = city;
    }
    continue;
    }
    if(reader.name() == "Location")
    {
    QString location = reader.readElementText();
    if (!location.isEmpty())
    {
    ui->locationComboBox->setEnabled(true);
    ui->locationComboBox->clear();
    ui->locationComboBox->insertItem(0,location);
    this->currentLocation = location;
    }
    Continue;
    }

        }
    

    } /*xml reader has reached its end, end of while loop */

            if(isStatusConnected)
            {
                   sendRequestCountryList();
            } 
                  if (reader.hasError()) {
                qDebug() << "reader returned error";
                errcode = HTTP_COMMUNICATION_ERROR;
      }
      if (errcode != 0) {
                com_class->ShowError(errcode);
                reply->deleteLater();
                this->setCursor(Qt::ArrowCursor);
                return;
      }
      this->setCursor(Qt::ArrowCursor);
      reply->deleteLater();
      return;
    

    }

    Note: the method sendRequestCountryList() creates another request and sends it to client. Basically we are sending second request from the method which handles the first request from server.

    @


  • Lifetime Qt Champion

    What is the exact error given by QXmlStreamReader ?


Log in to reply