最近在做一个文件批量上传的工具,要实现暂停继续、断点续传等功能。利用Qt自带的QtNetwork模块,完成这些需求并没有费多少周章,主要思路就是将文件分块,然后用while循环依次传输。具体实现代码比较复杂,简化了一下大致是这样子的:
1
|
int chunkUpload(UploadItem *item, const qint64 &chunkSize)
|
程序编译运行过程很顺利,测试的时候也没发现什么问题。但后来我随手上传了一个1G大小的文件,发现每次文件上传到70%左右的时候程序就崩溃了,小文件就没这个问题。急忙打开任务管理器,这才发现上传文件的时候,程序内存占用会随着上传进度的增加而增加,上传1G文件的时候内存最多会吃到1.5G,这时候程序申请不到更多内存了,我又没做检查,当然就会崩溃掉。
限制上传文件大小这种事我是不会做的,毕竟一个上传工具占用内存比PS都高实在不科学。注意到文件上传完成之后内存会立即回到正常值,显然原因并不是我忘记释放内存而是内存释放不及时,这样看来唯一可疑的地方就是上面chunkUpload
函数里面的reply->deleteLater()
那一句了吧。于是我写了个方法监听reply的销毁时机,果然每一块上传完成之后reply没有销毁,直到文件全部上传完毕之后才输出一大堆“I’m destroyed…”的信息。
根据Qt文档的说明,QObject::deleteLater()
并没有将对象立即销毁,而是向主消息循环发送了一个event,下一次主消息循环收到这个event之后才会销毁对象。我在这里使用deleteLater只是因为Qt文档里推荐这么做而已,其他并没多想。是这样的话一切都说得通了,因为chunkUpload
函数是在一个while循环里,程序还没来得及处理这个event就立即进行下一块传输了,传输过程中生成的QNetworkReply
以及它关联的QBuffer
、QHttpMultiPart
当然也就来不及删除了。崩溃原因找到了。你不就是来不及处理销毁对象的event嘛,手动让你处理下不就行了?于是修改upload
函数代码如下:
1
|
void upload()
|
编译、运行,内存占用依然没有改变,看样子加这一行用处不大。再次查询QObject::deleteLater()
的文档,发现这样一句话:
…for the object to be deleted, the control must return to the event loop from which deleteLater() was called.
这么说来,deleteLater
销毁QObject
的唯一时机就是程序返回主消息循环以后了呢。无奈只能放弃deleteLater
。考虑到每次return前都要手动delete亦或是使用goto语句实在都不够优雅,所以利用Qt自带的QScopedPointer
,修改chunkUpload
函数如下:
1
|
int chunkUpload(UploadItem *item, const qint64 &chunkSize)
|
问题解决。
https://blog.yeatse.com/2015/03/18/qobject-deletelater-usage/