发布请求和 QNetworkAccessManager 的内存泄漏
Posted
技术标签:
【中文标题】发布请求和 QNetworkAccessManager 的内存泄漏【英文标题】:Memory leak with post requests and QNetworkAccessManager 【发布时间】:2013-12-02 13:36:49 【问题描述】:我正在制作一个使用大量计时器的程序,并以 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);
【问题讨论】:
【参考方案1】:来自 Qt 文档http://qt-project.org/doc/qt-5.1/qtnetwork/qnetworkaccessmanager.html
注意:请求完成后,由 用户在适当的时候删除 QNetworkReply 对象。不要 直接在连接到finished()的槽内删除它。你可以 使用 deleteLater() 函数。
我建议在您的 replyFinished() 方法中调用 reply->deleteLater()
。
【讨论】:
但如果我将其删除,那么如何在我的计时器的下一个间隔内重复使用它?我不会得到一个错误说对象不存在吗? 在replyFinished()
中作为参数的QNetworkReply
是由Qt 创建的。你不重复使用它。正如文档所说,您有责任释放它。
非常感谢您的帮助。我试试看能不能修好。【参考方案2】:
您应该在使用后为 QNetworkReply 对象调用 deleteLater()。
注意:请求完成后,用户有责任在适当的时候删除 QNetworkReply 对象。不要在连接到finished()的槽内直接删除它。您可以使用 deleteLater() 函数。
更多信息在这里:http://harmattan-dev.nokia.com/docs/library/html/qt4/qnetworkaccessmanager.html
【讨论】:
但如果我将其删除,那么如何在我的计时器的下一个间隔内重复使用它?我不会收到一个错误说对象不存在吗? 每次发布请求都会得到新的回复对象 非常感谢您的帮助。我试试看能不能修好。【参考方案3】:谢谢大家的帮助。 很简单
中回复上的“deleteLater()”void replyFinished(QNetworkReply *reply)
它应该看起来像这样
void replyFinished(QNetworkReply *reply)
// after all of your processing
reply->deleteLater();
这是一个小问题,但让我发疯了很长时间,所以我希望这会有所帮助
【讨论】:
以上是关于发布请求和 QNetworkAccessManager 的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章
当内容类型和内容编码标头一起发送时,表达js拒绝发布请求(400错误请求)