QObject::deleteLater()並沒有將對象立即銷毀,而是向主消息循環發送了一個event,下一次主消息循環收到這個event之后才會銷毀對象 good


程序編譯運行過程很順利,測試的時候也沒發現什么問題。但后來我隨手上傳了一個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以及它關聯的QBufferQHttpMultiPart當然也就來不及刪除了。崩潰原因找到了。你不就是來不及處理銷毀對象的event嘛,手動讓你處理下不就行了?於是修改upload函數代碼如下:

1
2
3
4
5
6
7
void upload()
{
while (NOT_FINISHED) {
chunkUpload(item, CHUNK_SIZE);
qApp->processEvents(); // 讓主程序把消息隊列中的QEvent處理完
}
}

編譯、運行,內存占用依然沒有改變,看樣子加這一行用處不大。再次查詢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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int chunkUpload(UploadItem *item, const qint64 &chunkSize)
{
Q_ASSERT(item != 0);

// ...

QNetworkRequest request;
QScopedPointer<QNetworkReply> reply;
QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QBuffer* buffer = new QBuffer(multiPart);
QEventLoop loop;
QTimer timer;

// ... append fields to multiPart ...

request.setUrl(UPLOAD_URL);
reply.reset(networkManager->post(request, multiPart));
multiPart->setParent(reply.data());

// ... event loop ...

if (reply->isRunning())
reply->abort();

if (reply->error() != QNetworkReply::NoError)
return -1;

// ... deal with the reply ...

return 0;
}

問題解決。

 

https://blog.yeatse.com/2015/03/18/qobject-deletelater-usage/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM