這段時間做項目需要有一個進行快速采集信息的設備,但是在單獨測試的過程中發現程序的內存占用會一直增長,也就是所謂的內存泄露問題。這個問題困擾了我們幾個星期,我嘗試了通過事件循環重寫waitfor系列函數來解決這個問題,但是由於線程包含問題導致了新的問題。。。今天在Qt的官方論壇上搜索時發現15年就有人發現了這個問題,然后上傳了bug庫並得到了解決,所以特此記錄。
1.問題描述
通過形如下面的代碼進行串口的讀取或者寫入(高頻率),會導致運行exe的內存占用不斷提升,在一定時間后內存泄露到一定程度會導致軟件崩潰。
1 while (1) 2 { 3 if (port.waitForReadyRead(10)) 4 { 5 port->readAll(); 6 } 7 }
2.問題原因分析
因為waitfor系列函數是通過readyRead()信號與bytesWritten()信號來實現的,如果產生這兩個信號過快(就像上面的代碼,死循環執行瘋狂產生信號),會導致對應到槽函數的事件(信號到槽的執行是一種事件,我之前寫過,這個事件將會到對應線程的消息隊列中排隊等待執行)一直在消息隊列中瘋狂阻塞,阻塞的結果就是消息隊列不斷膨脹,從而內存不斷增加,直到隊列到達上限導致程序崩潰。
3.問題解決方案
知道原理后問題解決就很簡單了,說穿了就是讓線程去執行消息隊列中的事件而不是一直產生,而Qt專門為這種情況制定了一個函數:qApp->processEvents(),這個函數的意思就是讓調用此函數的線程執行其消息隊列中的事件,直至沒有事件可以執行為止。可見在死循環中加上這個函數之后,相關的內存泄露問題將迎刃而解,就像下面這樣:
1 while (1) 2 { 3 if (port.waitForReadyRead(10)) 4 { 5 qApp->processEvents(); 6 port->readAll(); 7 } 8 }