Утечка памяти с почтовыми запросами и QNetworkAccessManager

Я делаю программу, которая использует много таймеров и с интервалом в 4 секунды отправляет онлайн-сообщение в сценарий php. Я кодирую QtCreator 5.1. Я использую классы, подобные приведенным ниже.

Тот, что ниже, просто заполняет список задач, но в течение 8–12 часов объем памяти, который занимает программа, постоянно увеличивается и увеличивается.

Что я делаю неправильно при использовании этого класса? Я должен иметь возможность публиковать сообщения в Интернете, как я уже делаю, примерно каждые 4-8 секунд.

Вот простой класс для обслуживания одного из моих процессов:

Заголовочный файл: tasklistprocess.h

#ifndef TASKLISTPROCESS_H
#define TASKLISTPROCESS_H

#include <QThread>
#include <QtCore>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QListWidget>
#include <QTabWidget>

#include "globalhelper.h"
#include "securityinfo.h"

class TaskListProcess : public QThread
{
    Q_OBJECT
public:
    explicit TaskListProcess(QListWidget *obj_main, QTabWidget *tabs_main, QString user, QObject *parent = 0);

signals:
    void upTaskStorage(int key,QHash<QString,QString> item);

private:
    GlobalHelper gh;
    Securityinfo sci;
    QNetworkAccessManager *nam;
    QNetworkRequest request;
    QByteArray data;

    // this is the disposable params for reusage through out the class
    QUrlQuery params;
    QString post_data;
    QString user_name;
    QTimer *tasklist_tmr;

    bool get_task_list;

    QListWidget *obj;
    QTabWidget *tabs;

private slots:
    void setTaskList();
    void replyFinished(QNetworkReply *reply);
    void sendPost(QString file_name, QUrlQuery params);
};

#endif // TASKLISTPROCESS_H`

Исходный файл: tasklistprocess.cpp

#include "tasklistprocess.h"

TaskListProcess::TaskListProcess(QListWidget *obj_main, QTabWidget *tabs_main, QString user, QObject *parent) :
    QThread(parent)
{
    user_name = user;
    get_task_list = false;
    obj = obj_main;
    tabs = tabs_main;
    tasklist_tmr = new QTimer(this);

    connect(this,SIGNAL(started()),this,SLOT(setTaskList()));
    connect(tasklist_tmr,SIGNAL(timeout()),this,SLOT(setTaskList()));

    nam = new QNetworkAccessManager(this);
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
    request.setRawHeader( "User-Agent" , "Mozilla Firefox" );
    // here we connect up the data stream and data reply signals
    connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
}

void TaskListProcess::setTaskList()
{
    qDebug() << "Your task list was set";
    bool in = false;
    if(!(tasklist_tmr->isActive()))
    {
        tasklist_tmr->start(10000);
        in = true;
    }
    if(!(get_task_list))
    {
        params.clear();
        params.addQueryItem("user_name", user_name);
        params.addQueryItem("logged_in", "1");
        sendPost("getTaskList.php",params);
        get_task_list = true;
    }
    else
    {
        if(post_data.contains("|*|"))
        {
            //here i retrieve a piece of information from a php script which is stored in a custom string format
            // here we clear the list for the new data to be put in
            if(obj->count()>0)
            {
                obj->clear();
            }
            int key = 0;
            foreach(QString inner_task,post_data.split("|*|"))
            {
                QHash<QString,QString> task_cont;
                //qDebug() << "         ";
                if(inner_task.contains("*,*"))
                {
                    foreach(QString task_val,inner_task.split("*,*"))
                    {
                        if(task_val.contains("*=*"))
                        {
                            QStringList key_pairs = task_val.split("*=*");
                            task_cont.insert(key_pairs[0],key_pairs[1]);
                            if(key_pairs[0] == "tt")
                            {
                                QString val_in;
                                if(key_pairs[1].length()>10)
                                {
                                    // this sets the title to the shortened version
                                    // if the string length is too long
                                    val_in = key_pairs[1].left(10) + "....";
                                }
                                else
                                {
                                    val_in = key_pairs[1];
                                }
                                obj->addItem("Task :" + QString::fromUtf8(key_pairs[1].toStdString().c_str()));
                            }
                        }
                    }
                }
                //task_storage.insert(key,task_cont);
                emit upTaskStorage(key,task_cont);
                key ++;
            }
        }
        get_task_list = false;
    }
    // here we're checking to see if they are looking at the task tab so it doesn't keep changing
    // back and forth between the tabs
    bool change = true;
    if(tabs->currentIndex() != 0)
    {
        change = false;
    }

    if(change)
    {
        tabs->setCurrentIndex(0);
    }else if(in)
    {
        tabs->setCurrentIndex(0);
    }
}

void TaskListProcess::replyFinished(QNetworkReply *reply)
{
    if (reply->error() != QNetworkReply::NoError) {
            qDebug() << "Error in" << reply->url() << ":" << reply->errorString();
            return;
        }
    QString data = reply->readAll().trimmed();
    post_data = data;
    if(get_task_list)
    {
        setTaskList();
    }
}

void TaskListProcess::sendPost(QString file_name, QUrlQuery params)
{
    post_data = "";
    QUrl url(sci.getHost() + file_name);

    url.setQuery(params);

    data.clear();
    data.append(params.toString().toUtf8());

    request.setUrl(url);
    nam->post(request, data);
}

person TheMan68    schedule 02.12.2013    source источник


Ответы (3)


Из документов Qt http://qt-project.org/doc/qt-5.1/qtnetwork/qnetworkaccessmanager.html

Примечание. После завершения запроса пользователь должен удалить объект QNetworkReply в подходящее время. Не удаляйте его напрямую в слоте, подключенном к finished (). Вы можете использовать функцию deleteLater ().

Я бы посоветовал вызвать reply->deleteLater() в вашем методе replyFinished ().

person Dan Milburn    schedule 02.12.2013
comment
но если я удалю его, как я могу повторно использовать его в следующий интервал моего таймера? я бы не получил сообщение об ошибке, что объект не существует? - person TheMan68; 02.12.2013
comment
QNetworkReply, который у вас есть как параметр в replyFinished(), создается Qt. Вы не используете его повторно. И, как сказано в документации, вы несете ответственность за его освобождение. - person Marc Plano-Lesay; 02.12.2013
comment
Большое спасибо за Вашу помощь. Я попробую и посмотрю, смогу ли я это исправить. - person TheMan68; 03.12.2013

Вы должны вызвать deleteLater () для объекта QNetworkReply после использования.

Примечание. После завершения запроса пользователь должен удалить объект QNetworkReply в подходящее время. Не удаляйте его напрямую в слоте, подключенном к finished (). Вы можете использовать функцию deleteLater ().

Дополнительная информация здесь: http://harmattan-dev.nokia.com/docs/library/html/qt4/qnetworkaccessmanager.html

person weisert    schedule 02.12.2013
comment
но если я удалю его, как я могу повторно использовать его в следующем интервале моего таймера? я бы не получил сообщение об ошибке, что объект не существует? - person TheMan68; 02.12.2013
comment
Каждый раз, когда вы делаете почтовый запрос, вы получаете новый объект ответа в результате - person weisert; 02.12.2013
comment
Большое спасибо за Вашу помощь. Я попробую и посмотрю, смогу ли я это исправить. - person TheMan68; 03.12.2013

Всем спасибо за привет. Это было очень просто "deleteLater ()" в ответе в

void replyFinished(QNetworkReply *reply)
{

}

и это должно было выглядеть так

void replyFinished(QNetworkReply *reply)
{
    // after all of your processing 
    reply->deleteLater();
}

это была такая небольшая проблема, но она надолго сводила меня с ума, так что я надеюсь, что это поможет

person TheMan68    schedule 02.01.2014