如何解決QT內存泄漏的問題,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
前幾天,項目開展了一次代碼初次評審。會上,領導指出一些可能會帶來內存泄漏的代碼,如下圖所示:
圖中的pLayout在new的時候沒有指定任何父對象,且MainWindow的析構函數中也沒有對pLayout做delete操作,這意味著為pLayout申請的內存空間在程序運行期間是一直沒有得到釋放的。實際上,項目代碼中,還有許多這種“隱患”:一個單例類的成員變量在new的時候沒有指定父對象、一個靜態類的成員在new的時候沒有指定父對象……
這些“隱患”為何在目前程序運行時沒有暴露出問題?基于這個疑惑,我研究了QT的半自動化的內存管理,并結合實驗進行結果驗證,現將分析過程記錄下來
QObject及其派生類的對象,如果其parent非0,那么其parent析構時會析構該對象
QWidget及其派生類的對象,可以設置 Qt::WA_DeleteOnClose 標志位(當close時會析構該對象)
QAbstractAnimation派生類的對象,可以設置 QAbstractAnimation::DeleteWhenStopped
QRunnable::setAutoDelete()、MediaSource::setAutoDelete()
父子關系:父對象、子對象、父子關系。這是Qt中所特有的,與類的繼承關系無關,傳遞參數與parent有關(基類、派生類,或父類、子類,這是對于派生體系來說的,與parent無關)
堆空間的內存泄漏與改進方法實踐實例
繼承QWidget類的Test類,通過new為其分配內存,沒有設置WA_DeleteOnclose屬性且使用完后也沒有delete
實驗結果:關閉testWidget窗口后,沒有調用其析構函數打印“test delete”信息。直到程序結束之前testWidget的申請的內存空間都未被釋放
改進方法A
為testWidget窗口設置Qt::WA_DeleteOnClose屬性
實驗結果:關閉testWidget窗口后,調用了其析構函數,內存被釋放了
改進方法B
不設置Qt::WA_DeleteOnClose屬性,但是在new完testWidget后,程序退出前調用testWidget的delete函數
實驗結果:關閉testWidget窗口后,調用了其析構函數,內存也被釋放了
實驗結論:QWidget及其派生類的對象,可以設置 Qt::WA_DeleteOnClose 標志位(當close時會析構該對象)或者手動delete來釋放內存
??臻g的內存實踐實例不采用new,為testWidget分配??臻g,不設置Qt::WA_DeleteOnClose屬性,不手動delete
實驗結果:關閉窗口時調用了testWidget的析構函數,內存被釋放了
testWidget不采用new創建,直接將對象建議在??臻g,但設置Qt::WA_DeleteOnClose屬性或者使用后delete &testWidget
實驗結果:程序崩潰了,在第一次嘗試delete testWidget時就出錯
實驗結論:delete棧上分配的地址會出錯
父對象和子對象析構的實踐實例將testWidget的父對象設置為mainwindow
實驗結果:關閉窗口后,正常打印析構信息。程序退出前,先釋放testWidget的空間,再釋放mainwindow的空間(兩者都是分配到??臻g)
調整mainwindow和testWidget的構造順序
實驗結果:程序崩潰
分析原因:mainwindow析構時會將其子對象testWidget也析構,但testWidget是分配到??臻g上的,delete棧上的空間會出錯。
將testWidget分配到堆上,指定父對象為mainwindow,并在程序退出前delete mainwindow
實驗結果:delete mainwindow時,會將testWidget也一并delete
將testWidget作為mainwindow的成員,但在構造時不指定父對象,在main函數中delete mainwindow
實驗結果:應用程序退出前只有mainwindow被析構了
實驗結論:
析構函數總是出現在對象的生命期結束之時,靜態對象在程序運行結束之時析構。
對象的構造和析構的關系是棧數據結構中的入棧和出棧的關系。
指定了父對象的子對象,在父對象被析構時,會將其一并析構掉
新建一個malloc_class,將malloc_class作為mainwindow的成員,在mallocClass的構造函數里面用malloc申請500M內存,在mainwindow放置一個button,點擊button就delete malloc_class,在任務管理器中看500M內存是否有被釋放。對于malloc_class的new操作,測試了兩種情況:
new malloc_class時不指定父對象new malloc_class時指定它的父對象為mainwindow
實驗結果:兩種情況一樣的結果,點擊button,在delete testWidget后,在testThread中申請的500M空間都沒有被釋放
猜想是不是因為malloc的空間并沒有指定父對象,異想天開的又測試了另外一種情況:直接創建malloc_class時用malloc為其分配內存,再在button的槽函數里delete malloc_class
實驗結果:程序崩潰了……
查閱資料得知:malloc只能為POD類型數據(一個類或結構體通過二進制拷貝后還能保持數據不變,具體解釋自查資料)分配內存,其他的必須用new分配內存。Malloc函數分配內存空間時并不調用構造函數,同樣free函數再回收空間時也不調用析構函數。
實驗結論:malloc分配的內存空間都要自己管理,與QT的父子對象同步析構沒有關系。也就是說應該再次明確:指定父對象的并且基于QObject為基類的對象才會同步析構
注意:malloc的空間只是一個虛擬內存,一定要初始化或者寫數據才會有物理內存的體現
對于在應用程序中不是常駐的對象,應習慣為其指定父對象,或著用完之后手動delete;對于應用程序中常駐的對象,即便在應用程序結束后操作系統會釋放其使用的內存,也不建議隨性new沒有parent的對象??傊?,養成嚴格處理內存分配和釋放內存的好習慣,要清楚自己在編碼時使用了哪些內存,什么時候需要釋放,不定時關注程序的內存占用率。
看完上述內容,你們掌握如何解決QT內存泄漏的問題的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。