QNetworkAccessManager and Memory Leak



  • Hi everybody,
    I have a very big problem with QNetworkAccessManager. I create a Desktop Application to analyze some data about a web site. Well I use QNetworkAccessManager to access a simple page Login , I store to information too QNetworkReply in my variable on stack (viewstate,cookie ,ecc...) and then I use a Search page to analyze ( in the same domain of course).
    Well when I call QNetworkaccessManager->post() and analyze the QNetworkReply every time I call my function with a POST my memory increase !!!
    PS:
    I use QNetworkReply->deleteLater();

    This is MY CODE

    @
    // in file .h
    QNetworkAccessManager netman;

    //in file .cpp
    void myClass::myFunction(){
    QNetworkRequest netRequest(QUrl("https://myWebSite.com/Default.aspx"));
    netRequest.setRawHeader("Cache-Control", "no-cache");
    netRequest.setRawHeader("Pragma", "no-cache");
    netRequest.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)");
    netRequest.setRawHeader("Accept","/");
    netRequest.setRawHeader("Accept-Language","it-IT");
    netRequest.setRawHeader("Connection","keep-alive");
    netRequest.setRawHeader("Accept-Encoding","gzip");
    netRequest.setRawHeader("Cookie",cookie.toLatin1());
    netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    QString data="__EVENTTARGET=&__EVENTARGUMENT=&__LASTFOCUS=&__VIEWSTATE="+viewState+"&ctl00$body_box$DDL_tipo_ricerca=targa&ctl00$body_box$ricerca.x=68&ctl00$body_box$ricerca.y=19&ctl00$body_box$numero_targa="+targa.targa+"&__EVENTVALIDATION="+eventValidation;
    QByteArray dataPost = data.toLatin1();
    netRequest.setHeader(QNetworkRequest::ContentLengthHeader, dataPost.size());
    connect(&netman,SIGNAL(finished(QNetworkReply*)),this,SLOT(myResponse(QNetworkReply*)));
    netman.post(netRequest,dataPost);
    }

    void myClass::myResponse(QNetworkReply *reply){
    QString resp = reply->readAll();
    reply->abort();
    reply->close();
    reply->deleteLater();
    emit responseEvent(resp);
    this->deleteLater();
    }
    @

    Please help me! I don'know why this function generate memory leak. I tryed to destroyed my class after the call outsite the myResponse function but it same!



  • I don't think your memory leak is coming from this part of your code. deleteLater will be posted to the event loop that your reply object is a part of, which will call for a deletion after pending events are delivered to your reply object. It may be fine, but check on your use of this->deleteLater(). Do you want to delete your instance of myClass?



  • Yes , I would like to delete myClass after call myFunction().
    Who can check deletelater() function ?
    This is the rest of the program ... It shulde be right ...
    @#include "widget.h"
    #include "ui_widget.h"
    #include "myClass.h"

    Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
    {
    ui->setupUi(this);

    }

    Widget::~Widget()
    {
    delete ui;
    }

    void Widget::on_btnSimulate_clicked()
    {

    myClass *_class = new myClass(this);
    _class->cookie =cookie;
    _class->viewState=viewState;
    _class->eventValidation = eventValidation;
    _class->setTarga ("AAAAA");
    _class->myFunction();
    

    }
    @
    Well I debug step by setup and the memory increase after POST. When I call reply->delateLater(); after 2 or 3 seconds the memory decrease a bit... If I try to call this function about 10000 times my memory increase a lot !
    In process task I see the start memory is about 9000 kb after 10000 call is 450 000 kb !! And I don't save nothing! I don know why...



  • You may want to consider keeping a single instance of myClass since it holds the instance of QNetworkAccessManager. There should likely only be one QNetworkAccessManager per application.

    http://qt-project.org/doc/qt-5/qnetworkaccessmanager.html#details



  • Ok ... I try to change my code and test ...thank you :)



  • I have a question: are you calling it 10,000 times in order to make sure your program isn't leaking, or is this a common use of your test app?

    When you call the method 10,000 times in immediate succession, the QNetworkAccessManager side may need to post those as events onto its event queue, which is the space where events wait to get executed by an event loop. This means that the 10,000 requests will be posted to the event queue that QNetworkAccessManager is posting to before many (maybe all) of the deleteLater calls can post to the same event queue. The deleteLater calls will be allowed to happen, but this will possibly manifest after some time has passed when you're looking for the memory to clear.

    If you're debugging and trying to easily find out if the event loop is still processing events from the event queue, you can start the application normally, call the 10,000 requests, then set a breakpoint in your response function at some time later.



  • If you want to make sure that you only send a request after you receive a response, you can set up a flag to ensure this happens.

    If you need to send multiple requests, one after the other, you can emit a signal out of myResponse that you can connect to and use to start a new request. You can keep count and limit to a number of iterations in the slot you use to receive this signal.

    It'll look like this:

    In file .h
    @QNetworkAccessManager netman;
    bool waitingForResponse;
    int count;@

    In file .cpp
    @
    myClass::myClass() : waitingForResponse(false), count(0)
    {
    connect(&netman, SIGNAL(finished(QNetworkReply*)), this, SLOT(myResponse(QNetworkReply*)));
    connect(this, SIGNAL(responseFinished()), this, SLOT(doRequests()));
    }

    void myClass::myFunction(){
    if (!waitingForResponse)
    {
    waitingForResponse = true;

        QNetworkRequest netRequest(QUrl("https://myWebSite.com/Default.aspx"));
        netRequest.setRawHeader("Cache-Control", "no-cache");
        netRequest.setRawHeader("Pragma", "no-cache");
        netRequest.setRawHeader("User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)");
        netRequest.setRawHeader("Accept","*/*");
        netRequest.setRawHeader("Accept-Language","it-IT");
        netRequest.setRawHeader("Connection","keep-alive");
        netRequest.setRawHeader("Accept-Encoding","gzip");
        netRequest.setRawHeader("Cookie",cookie.toLatin1());
        netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
        QString data="__EVENTTARGET=&__EVENTARGUMENT=&__LASTFOCUS=&__VIEWSTATE="+viewState+"&ctl00$body_box$DDL_tipo_ricerca=targa&ctl00$body_box$ricerca.x=68&ctl00$body_box$ricerca.y=19&ctl00$body_box$numero_targa="+targa.targa+"&__EVENTVALIDATION="+eventValidation;
        QByteArray dataPost = data.toLatin1();
        netRequest.setHeader(QNetworkRequest::ContentLengthHeader, dataPost.size());
        connect(&netman,SIGNAL(finished(QNetworkReply*)),this,SLOT(myResponse(QNetworkReply*)));
        netman.post(netRequest,dataPost);
    }
    

    }

    void myClass::myResponse(QNetworkReply *reply){
    QString resp = reply->readAll();
    reply->abort();
    reply->close();
    reply->deleteLater();
    waitingForResponse = false;
    emit responseEvent(resp);
    emit responseFinished();
    }

    void myClass::doRequests(){
    if (count < 10000)
    {
    myFunction();
    ++count;
    }
    }@





  • the first image is the memory Begin Start and the second one is the memory after 1000 times calls.



  • Nobody can help me? I think is a bug in QNetworkAccessManager. Somebody know an alternative to create a network request?



  • Did you try waiting for a response before sending more requests? What does your new code look like? There is an alternative way to use QNetworkAccessManager, as explained in this article:

    http://www.johanpaul.com/blog/2011/07/why-qnetworkaccessmanager-should-not-have-the-finishedqnetworkreply-signal/


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.