程序編譯運行過程很順利,測試的時候也沒發現什么問題。但后來我隨手上傳了一個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/
