QNetworkAccessManager在QThread中重复调用post为何出现内存泄漏?
为何移至QThread实例的自定义对象中重复运行的这段代码会产生内存泄漏?
运行环境:Ubuntu 20.04、x86_64 CPU、Qt 5.14.2,每次调用以下代码约泄漏8字节,移除post()调用后未检测到泄漏。
泄漏复现代码:
void QCustomHTTPManager::compare() { // custom code to create request and multiPart content QNetworkReply *reply = networkaccessmanager->post(request,&multiPart); connect(reply,&QNetworkReply::finished,eventloop,&QEventLoop::quit); eventloop->exec(); emit compared(); reply->deleteLater(); }
无泄漏对照代码:
void QCustomHTTPManager::compare() { // custom code to create request and multiPart content QTimer::singleShot(1,eventloop,&QEventLoop::quit); eventloop->exec(); emit compared(); }
泄漏原因及修正方案
核心问题:
QNetworkReply的deleteLater()无法被执行deleteLater()的工作逻辑是向对象所在线程的事件队列发送删除事件,只有当该线程的事件循环处于运行状态时,这个事件才会被处理,进而销毁对象。- 你的代码中,
eventloop->exec()阻塞当前线程直到finished信号触发,循环退出后调用reply->deleteLater(),但此时当前线程的事件循环已经停止,没有机会处理删除事件,导致reply对象始终无法被释放,每次调用都会积累内存泄漏。 - 额外隐患:你传递栈对象
multiPart的地址给post(),如果未设置multiPart->setParent(reply),multiPart的资源无法随reply一同释放,会加重泄漏问题。
修正方法
- 放弃局部事件循环的阻塞方式,改用信号槽连接
reply的finished信号到处理函数,确保事件循环能正常处理删除事件:void QCustomHTTPManager::compare() { // custom code to create request and multiPart content multiPart->setParent(nullptr); QNetworkReply *reply = networkaccessmanager->post(request, multiPart); connect(reply, &QNetworkReply::finished, this, [=](){ emit compared(); reply->deleteLater(); }); } - 如果必须使用局部事件循环,在调用
deleteLater()后手动触发一次事件处理,让删除事件执行:void QCustomHTTPManager::compare() { // custom code to create request and multiPart content QNetworkReply *reply = networkaccessmanager->post(request,&multiPart); connect(reply,&QNetworkReply::finished,eventloop,&QEventLoop::quit); eventloop->exec(); emit compared(); reply->deleteLater(); QCoreApplication::processEvents(); // 手动处理事件队列,执行删除操作 } - 务必为
multiPart设置父对象为reply:multiPart->setParent(reply);,确保其随reply一同释放。
- 放弃局部事件循环的阻塞方式,改用信号槽连接
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

