讓我生不如死的Windows CE內存泄漏
很多實(shí)時(shí)嵌入式設備是長(cháng)時(shí)間不間斷運行的,即使是少許的內存泄漏,也會(huì )積少成多,對嵌入式系統帶來(lái)災難性的影響。這幾天,我在嵌入式軟件項目中就飽嘗到這個(gè)痛苦,讓我明白到嵌入式實(shí)時(shí)系統的應用軟件也會(huì )有許多內存問(wèn)題,從而導致嵌入式系統的崩潰。例如非法的內存訪(fǎng)問(wèn)、各種死鎖以及諸如堆棧溢出、數組越界和內存泄漏等。
本文引用地址:http://dyxdggzs.com/article/201610/305889.htmWindows CE作為最流行的一種嵌入式操作系統,現正廣泛被應用。我所負責的嵌入式應用程序也是在Windows CE平臺上開(kāi)發(fā)的。在進(jìn)入測試階段中,我發(fā)現有一個(gè)程序模塊系統內存和CPU資源消耗急劇增加,持續增長(cháng)到出現OutOfMemoryError為止,然后自動(dòng)重啟。這個(gè)問(wèn)題折騰到我生不如死,痛苦不堪?;宋液脦讉€(gè)通宵達旦的加班后,經(jīng)過(guò)分析終于確認Windows CE內存泄漏是造成這次Windows CE系統崩潰的主要原因。這里與大家分享我在開(kāi)發(fā)過(guò)程中遇到的內存泄漏的檢測和處理解決過(guò)程。
一.Windows CE如何進(jìn)行內存分配?
為了判斷是否有內存泄露,我們首先需要了解Windows CE是如何管理內存的。許多嵌入式程序員都有一個(gè)共識,就是如果評選在Windows CE 程序中遇到最多的問(wèn)題,那其中一個(gè)問(wèn)題一定有內存問(wèn)題。
(1)什么是Windows CE內存管理
一般來(lái)說(shuō),運行Windows CE的嵌入式設備出于緊湊型的考慮內存都不大,以至于有時(shí)候有些程序員會(huì )為了節省內存開(kāi)支而犧牲程序的某些性能。但盡管WinCE系統的內存很小,用來(lái)管理內存的函數卻十分完善。Windows CE實(shí)現了Windows XP中幾乎全部的Win32內存管理API。例如,Windows CE支持虛擬內存分配,本地和分離的堆管理,甚至還有內存映射文件。像Windows XP一樣,Windows CE支持帶有應用程序間內存保護功能的32位地址空間,這一點(diǎn)對于多程序和多線(xiàn)程運行時(shí)是非常重要的功能。但是Windows CE畢竟是被設計來(lái)應用于實(shí)時(shí)場(chǎng)合的,所以它底層的內存結構又不同于Windows XP。
Windows CE內核可以在Flash上直接運行,也可以加載到內存中運行。Flash的運行方式,是把內核的可執行映像燒寫(xiě)到Flash上,系統啟動(dòng)時(shí)從Flash的某個(gè)地址開(kāi)始執行。在這種情況下,Windows CE系統就像直接讀硬盤(pán),存儲在Flash上的程序能夠以現場(chǎng)執行的方式運行。這種能力對小型系統來(lái)說(shuō)使之在具有巨大的優(yōu)勢,這樣這能快速啟動(dòng)一個(gè)應用程序,因此這種方法被很多嵌入式系統所采用。另一種是內核加載方式,是把內核的壓縮文件存放在Flash上,系統啟動(dòng)時(shí)讀取壓縮文件在內存里解壓,然后開(kāi)始執行。
(2)虛擬內存和函數應用
和大多數現代操作系統一樣,Windows CE實(shí)現按需調頁(yè)的虛擬內存機制。由于Windows CE系統使用了虛擬內存,這就給應用程序造成了一個(gè)假象,以為計算機安裝的內存遠遠超過(guò)自己所需要的數量。Windows CE是32位的操作系統,因此支持4GB的虛擬地址空間。Windows把這些地址空間分給進(jìn)程和系統使用,每個(gè)部分可以獲得2GB的虛擬內存。
虛擬內存是內存類(lèi)型中最基礎的。Windows CE 實(shí)現了系統的虛擬內存管理,在一個(gè)虛擬內存系統中,應用程序主要處理這個(gè)虛擬的地址空間,并不涉及到由硬件管理的物理內存。系統調用虛擬內存API來(lái)為其它類(lèi)型內存分配內存,包括堆和棧。Windows CE虛擬內存頁(yè)可以處在三種狀態(tài):自由(free),保留(reserved),或被提交(committed)。
簡(jiǎn)單說(shuō),就是當一個(gè)應用程序要查詢(xún)系統的內存時(shí),可使用虛擬內存API,包括VirtualAlloc,VirtualFree和VirtualReSize函數,這些函數可以直接操作虛擬內存空間的虛擬內存頁(yè)面。例如,頁(yè)面可以保留,提交給物理內存,或使用這些函數釋放。Windows CE實(shí)現了Win32的GetSystemInfo和GlobalMemoryStatus函數。另一個(gè)檢測系統狀態(tài)的函數是:void GlobalMemoryStatus(LPMEMORYSTATUS lpmst),通過(guò)GlobalMemoryStatus返回的信息可以驗證Windows CE內存結構。
(3)釋放虛擬內存
不同于Windows XP,Windows CE只支持在堆中分配固定(fixed)的塊。這簡(jiǎn)化了內存塊在堆中的處理,但是這使得堆在分配和釋放一段時(shí)間后會(huì )產(chǎn)生碎片。當堆里已經(jīng)清空的時(shí)候,仍然會(huì )占用大量的虛擬內存頁(yè),因為系統不能在堆中內存頁(yè)沒(méi)有完全釋放的時(shí)候回收這些頁(yè)。這時(shí),一般情況下是可以通過(guò)調用VirtualFree來(lái)取消提交,或釋放虛擬內存。從物理RAM頁(yè)中取消提交或者取消映射,但是保持頁(yè)被保留的狀態(tài),當在區域中的所有的頁(yè)通過(guò)VirtualFree被釋放時(shí),也應該處在同樣的情況下。更確切地說(shuō),區域中的全部頁(yè)要被釋放,那這些頁(yè)要么都是被提交的頁(yè),要么都是被保留的頁(yè)。如果有些頁(yè)被提交,有些頁(yè)被保留,那么VirtualFree函數調用就會(huì )失敗。
實(shí)際上,Windows CE會(huì )監視系統自由的內存,并對越來(lái)越少的內存作出響應。當很少內存可用時(shí),Windows CE首先發(fā)送WM_HIBERNATE消息,接下來(lái)會(huì )限制可能的內存分配。當應用程序被發(fā)送了一個(gè)WM_HIBERNATE消息后,系統將檢測內存級別,確認是否可用內存在限度之上,如果可用內存不足,WM_HIBERNATE消息將被發(fā)送給下一個(gè)程序,這會(huì )持續到所有程序被發(fā)送了WM_HIBERNATE消息。
評論