




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
.12022/12/19MOCOR平臺內(nèi)存管理介紹MOCOR內(nèi)存管理的基本架構(gòu)
ThreadX的內(nèi)存管理MOCOR的內(nèi)存管理MOCOR內(nèi)存bug實例分析.22022/12/19MOCOR內(nèi)存管理的基本架構(gòu)一般的嵌入式系統(tǒng)中最基本的內(nèi)存管理方案有兩種——靜態(tài)分配和動態(tài)分配。靜態(tài)分配是指在編譯或鏈接時將程序所需的內(nèi)存空間分配好。采用這種分配方案的內(nèi)存段,其大小一般在編譯時就能夠確定。靜態(tài)分配比較簡單,一般不需要特殊的管理。動態(tài)分配是指系統(tǒng)運行時根據(jù)需要動態(tài)地分配內(nèi)存,為實現(xiàn)動態(tài)分配,系統(tǒng)里需要有一套完善的管理機制。本文中所指的內(nèi)存管理,就是指動態(tài)分配內(nèi)存的管理。.32022/12/19MOCOR內(nèi)存管理的基本架構(gòu)MOCOR內(nèi)存管理體系的一個大致的調(diào)用層次如下圖所示:.42022/12/19MOCOR內(nèi)存管理的基本架構(gòu)從可用的內(nèi)存資源的角度,還可以得到下面的一個內(nèi)存分配圖。.52022/12/19MOCOR平臺內(nèi)存管理介紹MOCOR內(nèi)存管理的基本架構(gòu)ThreadX的內(nèi)存管理
MOCOR的內(nèi)存管理MOCOR內(nèi)存bug實例分析.62022/12/19ThreadX的內(nèi)存管理
內(nèi)存字節(jié)池(BTYEPOOL)內(nèi)存塊池(BLOCKPOOL).72022/12/19ThreadX的內(nèi)存管理內(nèi)存字節(jié)池(BTYEPOOL).82022/12/19ThreadX的內(nèi)存管理---內(nèi)存字節(jié)池1.基本概念:內(nèi)存字節(jié)池是一個連續(xù)的內(nèi)存塊。在字節(jié)池中,內(nèi)存的分配以字節(jié)為單位,任意大小的內(nèi)存都可以在字節(jié)池上分配(受限于內(nèi)存的容量)。內(nèi)存字節(jié)池類似于C語言里的堆(heap),所以,字節(jié)池我們也可以把它叫做字節(jié)堆,代碼里我們也可以看到創(chuàng)建的字節(jié)池通常以heap來命名。但與一般意義上的堆的不同在于,ThreadX里的字節(jié)池可以有多個,MOCOR平臺也是利用了這一特性,根據(jù)不同的需求而創(chuàng)建了多個heap。每一個字節(jié)池都有一個相應(yīng)的字節(jié)池控制塊,通常是一個全局結(jié)構(gòu)??刂茐K包括對內(nèi)存池的定義和狀態(tài),比如內(nèi)存池的名字,可用的字節(jié)數(shù)等。該結(jié)構(gòu)的定義如下:.92022/12/19ThreadX的內(nèi)存管理---內(nèi)存字節(jié)池.102022/12/19ThreadX的內(nèi)存管理---內(nèi)存字節(jié)池2.分配方式:從字節(jié)池中分配內(nèi)存類似于C語言的malloc調(diào)用,該調(diào)用返回所需內(nèi)存的數(shù)量(以字節(jié)為單位)。分配的原則是“首次符合”原則,就是說,當(dāng)?shù)谝粋€空閑內(nèi)存塊的大小滿足需求時,就從該內(nèi)存塊分配內(nèi)存,然后將該內(nèi)存塊的剩余內(nèi)存轉(zhuǎn)換成一個新塊。字節(jié)池在初始狀態(tài)下,只有一個空閑塊,以后隨著隨著分配的進行,內(nèi)存塊會隨之增多。除了上述的分配原則之外,字節(jié)池里還定義了一個值BYTE_POOL_SLIP_SIZE。這是在代碼里實現(xiàn)指定的一個具體數(shù)值,在分配內(nèi)存時,如果要分配的內(nèi)存大小大于這一數(shù)值,則從字節(jié)池的底部開始分配。采用這種分配方式是為了減少內(nèi)存碎片的產(chǎn)生,盡量把大內(nèi)存的分配區(qū)域和小內(nèi)存的分配區(qū)域分開。目前系統(tǒng)里定義的BYTE_POOL_SLIP_SIZE為80K。.112022/12/19ThreadX的內(nèi)存管理---內(nèi)存字節(jié)池3.內(nèi)存布局:以一個分配了兩次的字節(jié)池為例,在內(nèi)存中的情況如下:.122022/12/19ThreadX的內(nèi)存管理---內(nèi)存字節(jié)池注意:首先要注意的問題是碎片,一個字節(jié)池可能有2000字節(jié)的可用空間,但不保證一定能分配到2000字節(jié)的連續(xù)空間,內(nèi)存池對連續(xù)字節(jié)的數(shù)量不做保證。分配一塊內(nèi)存所需要的時間跟分配內(nèi)存的大小,字節(jié)池中的碎片數(shù)等因素有關(guān),如果字節(jié)池有2000字節(jié)的空閑塊,花多長時間找到這塊內(nèi)存也是沒有保證的。因此,在時間要求苛刻的任務(wù)中應(yīng)避免使用字節(jié)池。字節(jié)池不能在中斷函數(shù)里使用,也不能在timer回調(diào)函數(shù)里使用。.132022/12/19ThreadX的內(nèi)存管理---內(nèi)存字節(jié)池思考:假定系統(tǒng)中有一個內(nèi)存字節(jié)池,并且已經(jīng)從中分配了幾次內(nèi)存。當(dāng)內(nèi)存池中還有500字節(jié)的剩余內(nèi)存時,應(yīng)用程序申請200字節(jié)的內(nèi)存,在什么情況下,這樣的申請不能滿足?.142022/12/19ThreadX的內(nèi)存管理內(nèi)存塊池(BLOCKPOOL).152022/12/19ThreadX的內(nèi)存管理---內(nèi)存塊池1.基本概念:內(nèi)存塊池也是一個連續(xù)的字節(jié)塊,但它是由一定數(shù)量的固定szie的內(nèi)存塊組成的。因此,從一個內(nèi)存塊池中分配出的內(nèi)存總是固定大小的。相比字節(jié)池,內(nèi)存塊池的兩個主要優(yōu)勢是:沒有碎片。因為內(nèi)存塊池是固定size的塊構(gòu)成,所以沒有碎片的產(chǎn)生。分配和釋放的速度很快。所需的時間相當(dāng)于簡單的鏈表操作,分配時不需要搜索整個內(nèi)存塊列表,它總是使用鏈表頭部的內(nèi)存塊來分配。內(nèi)存塊池的主要缺點是缺乏靈活性。固定尺寸既是它的優(yōu)點也是它的缺點。如果一個內(nèi)存塊池的尺寸足夠大,可以滿足用戶最極限的內(nèi)存分配需求,那么,這個內(nèi)存塊池上分配許多不同尺寸的內(nèi)存會導(dǎo)致嚴重的內(nèi)存浪費。一種解決辦法是同時創(chuàng)建幾個不同的內(nèi)存塊池,每個內(nèi)存塊池分別容納不同尺寸的內(nèi)存塊。目前MOCOR平臺就是這樣做的,具體我們后面再討論。同字節(jié)池一樣,內(nèi)存塊池也有一個控制塊結(jié)構(gòu),其中有該內(nèi)存塊的相關(guān)信息,該結(jié)構(gòu)如下:.162022/12/19ThreadX的內(nèi)存管理---內(nèi)存塊池.172022/12/19ThreadX的內(nèi)存管理---內(nèi)存塊池2.分配方式:內(nèi)存塊池中分配內(nèi)存是非??斓模饕靡嬗趦?nèi)存塊池中的所有空閑內(nèi)存塊組成一個鏈表(即上面結(jié)構(gòu)中的tx_block_pool_available_list)。每次分配時只需要取鏈表頭即可,無須遍歷內(nèi)存塊池來找到空閑塊。.182022/12/19ThreadX的內(nèi)存管理---內(nèi)存塊池3.內(nèi)存布局:.192022/12/19ThreadX的內(nèi)存管理---內(nèi)存塊池思考如何計算一個內(nèi)存塊池所占用的物理內(nèi)存大小?.202022/12/19MOCOR平臺內(nèi)存管理介紹MOCOR內(nèi)存管理的基本架構(gòu)ThreadX的內(nèi)存管理MOCOR的內(nèi)存管理MOCOR內(nèi)存bug實例分析.212022/12/19MOCOR內(nèi)存管理MOCOR平臺在ThreadX內(nèi)存管理的基礎(chǔ)上,又做了進一步的封裝,這樣可以更便于上層應(yīng)用調(diào)用。前面我們已經(jīng)了解了ThreadX是如何對內(nèi)存進行管理的,下面我們從底層來到上層,看一看MOCOR是如何利用Threadx的內(nèi)存管理機制來建立自己的內(nèi)存管理方式。之前的MOCOR文檔里,將內(nèi)存字節(jié)池稱為堆(heap),而將內(nèi)存塊池稱為內(nèi)存池(pool),我們也延續(xù)這種說法,請注意不要混淆。.222022/12/19MOCOR內(nèi)存管理1.堆內(nèi)存(heap)管理:MOCOR平臺的堆內(nèi)存就是前面講到的內(nèi)存字節(jié)池。最早的MOCOR平臺只有一個內(nèi)存堆,但在實際使用中發(fā)現(xiàn),程序運行時往往要交錯的分配一些動態(tài)內(nèi)存和常駐內(nèi)存,這樣會產(chǎn)生很多無法消除的內(nèi)存碎片。同時base等通訊模塊同上層應(yīng)用又是并發(fā)的,這樣無規(guī)律的分配也會造成很多內(nèi)存碎片。為了解決這種情況,后來MOCOR版本將內(nèi)存堆分成了三塊,也就是創(chuàng)建了三個內(nèi)存字節(jié)池作為heap。這三個字節(jié)池的分別是:dynamicbaseheap,staticheap和dynamicappheap。同樣,對應(yīng)著三個heap也有三個不同的接口,分別是:SCI_ALLOC_BASE,SCI_ALLOC_CONSTSCI_ALLOC_APP。.232022/12/19MOCOR內(nèi)存管理三個heap:Baseheap:主要給PS,Layer1等使用。這個heap我們一般不用關(guān)心。Staticheap:主要用于分配常駐的內(nèi)存,即一旦分配就不再釋放的內(nèi)存。Appheap:其他不屬于以上兩種情況的內(nèi)存都在這里分配。.242022/12/19MOCOR內(nèi)存管理三個heap的大小都定義在mem_cfg.c里:#defineMAX_STATIC_HEAP_SIZE (600*1024)#defineMAX_DYNAMIC_BASE_HEAP_SIZE(60*1024)#defineMAX_DYNAMIC_APP_HEAP_SIZE (1430*1024)#define BYTE_HEAP_SIZE(MAX_STATIC_HEAP_SIZE+MAX_DYNAMIC_BASE_HEAP_SIZE+MAX_DYNAMIC_APP_HEAP_SIZE).252022/12/19MOCOR內(nèi)存管理系統(tǒng)assert之后,選擇菜單5,可以看到所有heap上的內(nèi)存分配信息,類似這樣:.262022/12/19MOCOR內(nèi)存管理思考:前面講了MOCOR里有三個不同用途的heap,想一想哪些內(nèi)存是要在staticheap里分配的,如果這些內(nèi)存改在appheap上會有什么問題?嘗試舉出幾個實際的例子來說明。.272022/12/19MOCOR內(nèi)存管理2.內(nèi)存池管理:這個所說的內(nèi)存池(pool)就是特指前面提到的內(nèi)存塊池。之前我們提到過,為了避免浪費內(nèi)存,通常是分配多個內(nèi)存池,分別對應(yīng)不同的大小。MOCOR平臺一共創(chuàng)建了12個內(nèi)存池,其對應(yīng)的大小和包含的內(nèi)存塊的數(shù)目都定義在mem_cfg.c里:#definePOOL_1_BLOCK_SIZE16//pool'sblocksize#definePOOL_1_BLOCK_NUM480//pool'sblocknumber#definePOOL_2_BLOCK_SIZE24//pool'sblocksize#definePOOL_2_BLOCK_NUM320//pool'sblocknumber#definePOOL_3_BLOCK_SIZE40//pool'sblocksize#definePOOL_3_BLOCK_NUM650//pool'sblocknumber#definePOOL_4_BLOCK_SIZE60//pool'sblocksize#definePOOL_4_BLOCK_NUM500//pool'sblocknumber#definePOOL_5_BLOCK_SIZE112//pool'sblocksize#definePOOL_5_BLOCK_NUM80//pool'sblocknumber#definePOOL_6_BLOCK_SIZE180//pool'sblocksize#definePOOL_6_BLOCK_NUM280//pool'sblocknumber#definePOOL_7_BLOCK_SIZE300//pool'sblocksize#definePOOL_7_BLOCK_NUM80//pool'sblocknumber#definePOOL_8_BLOCK_SIZE600//pool'sblocksize#definePOOL_8_BLOCK_NUM120//pool'sblocknumber#definePOOL_9_BLOCK_SIZE800//pool'sblocksize#definePOOL_9_BLOCK_NUM100//pool'sblocknumber#definePOOL_A_BLOCK_SIZE1100//pool'sblocksize#definePOOL_A_BLOCK_NUM98//pool'sblocknumber#definePOOL_B_BLOCK_SIZE1300//pool'sblocksize#definePOOL_B_BLOCK_NUM10//pool'sblocknumber#definePOOL_C_BLOCK_SIZE1600//pool'sblocksize#definePOOL_C_BLOCK_NUM12//pool'sblocknumber(以上的定義不同版本的MOCOR可能并不一致,經(jīng)常會有調(diào)整).282022/12/19MOCOR內(nèi)存管理什么時候在heap上分配,什么時候在內(nèi)存池上分配?MOCOR對分配內(nèi)存的位置有如下的約定:只有分配的內(nèi)存的大小超過mem_cfg.c里定義的最大的內(nèi)存塊池的大小,內(nèi)存才會在heap里分配,否則就在內(nèi)存塊池里分配。目前MOCOR平臺定義的最大的內(nèi)存塊池是1600字節(jié),也就是大于1600字節(jié)的內(nèi)存才在heap里分配。.292022/12/19MOCOR內(nèi)存管理MOCOR在內(nèi)存池上的分配策略是:最小適配原則:按從小到大的順序,遍歷所有的內(nèi)存池,直到找到一個內(nèi)存池,其大小大于欲分配內(nèi)存的大小,就在該內(nèi)存池分配內(nèi)存。如果該內(nèi)存池已被用盡,則繼續(xù)向下遍歷,找到下一個適合的內(nèi)存池。如果全部遍歷完都沒有找到可用的內(nèi)存池,則改為在heap上分配內(nèi)存。上面的策略對于上層的申請者是透明的,申請者只要傳入欲分配的內(nèi)存大小即可,無須關(guān)心內(nèi)存究竟是在哪里分配的。.302022/12/19MOCOR內(nèi)存管理系統(tǒng)assert之后,選擇菜單5,可以看到當(dāng)前所有pool的信息,類似這樣:.312022/12/19MOCOR內(nèi)存管理3.內(nèi)存Debug信息:為了方便在出現(xiàn)內(nèi)存問題的時候調(diào)試,通常在分配內(nèi)存的時候(heap和pool),會額外的多分配一個header,放在每一塊分配內(nèi)存的開始。header的結(jié)構(gòu)定義如下:結(jié)構(gòu)成員的意義如下:pre,succ:兩個指向header結(jié)構(gòu)的指針,目的是將所有的header串成一張雙向鏈表。file_name,line:分配該塊內(nèi)存的文件名和行號size:內(nèi)存大小(不包括header)block_num:系統(tǒng)分配的內(nèi)存塊總計此外,為了能檢查內(nèi)存越界,在每一塊分配內(nèi)存的最后也會額外多分配一個字節(jié)做為ENDFLAG,內(nèi)存分配時該字節(jié)會被寫入0xAA。當(dāng)該內(nèi)存被釋放時,會檢查該標志位,如果不為0xAA,則說明出現(xiàn)異常,系統(tǒng)ASSERT。.322022/12/19MOCOR內(nèi)存管理加入debug信息后的內(nèi)存如下:.332022/12/19MOCOR內(nèi)存管理因為有額外加了這些debug信息,所以如果我們要分配N個字節(jié)的內(nèi)存,那么實際上分配的大小是:N+sizeof(MEM_HEADER_T)+1.再考慮到字節(jié)對齊的需要,實際的空間比上面的數(shù)字可能還要大一點。比如16字節(jié)的內(nèi)存池,其中每個內(nèi)存塊的大小其實是:16+24+4(本應(yīng)是加1,加4是為了字節(jié)對齊)Header里的pre指向前一塊分配的內(nèi)存,next指向后一塊分配的內(nèi)存,所有分配的內(nèi)存,都通過header里的pre和succ指針串起來,構(gòu)成一張雙向鏈表。每分配一塊新的內(nèi)存,就將這塊內(nèi)存的header加到鏈表的最后。通過遍歷header構(gòu)成的鏈表,我們可以得到當(dāng)前所有分配的內(nèi)存塊的信息。.342022/12/19MOCOR內(nèi)存管理系統(tǒng)assert之后,選擇菜單4,就可以打印出這些信息,類似這樣:.352022/12/19MOCOR內(nèi)存管理思考:應(yīng)用里分配一塊大小為N字節(jié)的內(nèi)存,實際在內(nèi)存里占了多少空間?.362022/12/19MOCOR內(nèi)存管理練習(xí):前面我們已經(jīng)講了MOCOR平臺各類內(nèi)存的分配情況,下面需要你親自動手加深理解。使用我們的樣機,連上log,主動assert,輸入3,dump出當(dāng)前的內(nèi)存。輸入5,打出當(dāng)前的內(nèi)存信息。然后打開內(nèi)存dump文件,找到appheap的起始地址,從起始地址開始,推出整個appheap的所有內(nèi)存塊的信息,然后用剛才打印出的信息驗證一下你的推導(dǎo)是否正確。.372022/12/19MOCOR內(nèi)存管理4.物理內(nèi)存:內(nèi)存管理的最終的對象就是物理內(nèi)存,但是,物理內(nèi)存并不能全部用于動態(tài)分配,因為一些全局變量,代碼等需要占用物理內(nèi)存,這些相當(dāng)于靜態(tài)分配。而我們通常說的內(nèi)存管理是指動態(tài)的對內(nèi)存進行分配和釋放。那么哪些物理內(nèi)存是我們能夠動態(tài)分配使用的呢,我們是如何知道可以動態(tài)分配的物理內(nèi)存的地址范圍呢?以6600L芯片為例,L所用的NORMCP中的SRAM通常是4M,這4M就是我們所能夠用到的所有物理內(nèi)存。OS啟動后,會把物理內(nèi)存SRAM的地址映射到0x04000000到0x04400000這個區(qū)域。.382022/12/19MOCOR內(nèi)存管理Heap和pool對應(yīng)的物理內(nèi)存的位置和大小:uint32pool_1_addr[POOL_XX_SIZE(POOL_1_BLOCK_SIZE,POOL_1_BLOCK_NUM)];uint32pool_2_addr[POOL_XX_SIZE(POOL_2_BLOCK_SIZE,POOL_2_BLOCK_NUM)];uint32pool_3_addr[POOL_XX_SIZE(POOL_3_BLOCK_SIZE,POOL_3_BLOCK_NUM)];………uint32pool_B_addr[POOL_XX_SIZE(POOL_B_BLOCK_SIZE,POOL_B_BLOCK_NUM)];uint32pool_C_addr[POOL_XX_SIZE(POOL_C_BLOCK_SIZE,POOL_C_BLOCK_NUM)];uint32BYTE_HEAP_ADDR[byte_head_size>>2];.392022/12/19MOCOR內(nèi)存管理5.內(nèi)存委托管理:委托內(nèi)存管理實質(zhì)就是給了模塊創(chuàng)建自己的heap和pool的機會。通常情況下我們使用的heap和pool都是系統(tǒng)創(chuàng)建的。但有些模塊也想先從系統(tǒng)的heap里分出一塊大內(nèi)存,然后在這塊大內(nèi)存上,再根據(jù)自己的需要細分出一些內(nèi)存塊來供本模塊使用。在沒有委托內(nèi)存管理之前,這種細分的工作實際由各模塊自己來完成,實現(xiàn)的手法也五花八門。有了委托內(nèi)存管理,模塊可以在分配的大內(nèi)存的基礎(chǔ)上,再創(chuàng)建自己的heap和pool,這些heap和pool的實現(xiàn)機制,同我們之前講的系統(tǒng)的機制是基本一樣的。.402022/12/19MOCOR內(nèi)存管理6.BLOCKMEM:關(guān)于BLOCKMEM可以參考《MOOCR應(yīng)用模塊內(nèi)存使用接口》的第二章,如果還不清楚blockmem的目的和用法的,請務(wù)必先學(xué)習(xí)上面這篇文檔。.412022/12/19MOCOR內(nèi)存管理幾個容易混淆的地方:1.BLOCKMEM并不是在內(nèi)存中實際分配出一塊區(qū)域來進行管理(雖然舊的MOCOR版本上確實是這樣的),BLOCKMEM的分配依然是在appheap上完成的。既然是在appheap上分配的,那么assert之后按5,從appheap的信息里是可以找到當(dāng)前分配的blockmem的,比如這樣:.422022/12/19MOCOR內(nèi)存管理.432022/12/19MOCOR內(nèi)存管理2.BLOCKMEM的管理機制中,為各塊mem都定義了一個offset,但這個offset純粹是一個邏輯概念,它的作用是在分配blockmem時判斷是否存在mem沖突。一個block在內(nèi)存中的實際位置同這個offset沒有任何關(guān)系。.442022/12/19MOCOR內(nèi)存管理MOCOR內(nèi)存管理的基本架構(gòu)ThreadX的內(nèi)存管理MOCOR的內(nèi)存管理MOCOR內(nèi)存bug實例分析.452022/12/19MOCOR內(nèi)存bug實例分析內(nèi)存不足:
內(nèi)存不足是經(jīng)常遇到的問題,內(nèi)存不足根據(jù)產(chǎn)生的原因,還可以分為內(nèi)存泄露引起的不足,內(nèi)存碎片引起的不足,以及真正的內(nèi)存不足。下面我們以幾個具體的例子來分析。.462022/12/19MOCOR內(nèi)存bug實例分析1.內(nèi)存泄漏:內(nèi)存泄露是指分配了一塊內(nèi)存在使用完后卻沒有釋放,造成系統(tǒng)中可用內(nèi)存越來越少,最后死機。內(nèi)存泄露引起的死機很容易定位,只要在死機后輸入4,打出當(dāng)前所有分配的內(nèi)存信息,查看是否有大量的重復(fù)的內(nèi)存分配就可以知道。實例:某客戶項目,測試中反復(fù)撥號出現(xiàn)死機,死機信息為:File:RTOS\source\src\c\threadx_mem.cLine:494ASSERT(ASSERT:Error0x10(Nomemory,unabletoallocate!),mmipb_wintab.c,line=11550,param=0x4650)打出當(dāng)前所有分配的信息,發(fā)現(xiàn)異常,有一條分配信息出現(xiàn)多次:.472022/12/19MOCOR內(nèi)存bug實例分析.482022/12/19MOCOR內(nèi)存bug實例分析2.內(nèi)存碎片:如果系統(tǒng)中存在內(nèi)存碎片,可能會出現(xiàn)雖然剩余的總內(nèi)存數(shù)是足夠的,但依然分配不出內(nèi)存的情況。實例,某客戶項目,后臺運行QQ,進入DC后死機。File:RTOS\source\src\c\threadx_mem.cLine:494ASSERT(ASSERT:Error0x10(Nomemory,unabletoallocate!),block_mem.c,line=563,param=0x113004)從死機信息可以看出,要分配的內(nèi)存大小為0x113004(1126404),這么大的內(nèi)存只可能從heap上分配,查看appheap的信息如下:.492022/12/19MOCOR內(nèi)存bug實例分析.502022/12/19MOCOR內(nèi)存bug實例分析我們重點關(guān)注畫紅圈的三塊內(nèi)存,可以看到,剩余的總內(nèi)存1495344,大于欲分配的內(nèi)存,但是編號1和3的兩塊空閑內(nèi)存正好被編號2的內(nèi)存隔開了,1,和3的大小都不超過1126404,所以無法分配,這就是一個典型的內(nèi)存碎片造成內(nèi)存不足的場景。要解決這個問題,我們就要想辦法把兩塊空閑內(nèi)存連在一起,主要就是要調(diào)整這幾塊內(nèi)存的分配和釋放的順序。我們不妨用逆向思維來分析,先看一下造成內(nèi)存碎片的順序是怎樣的,然后我們只要避免這種順序就可以了。首先在最初時,1,2,3這三塊內(nèi)存實際是一整塊空閑內(nèi)存。前面我們提過,字節(jié)池分配內(nèi)存時有一個反向分配的概念,當(dāng)要分配的的內(nèi)存大于80K時,是從底向上分配的。所以分配和釋放的順序是:第一步:分配內(nèi)存3;第二步:分配內(nèi)存2;第三步:釋放內(nèi)存3由此可以自然的想到解決的辦法,就是調(diào)整上面的3個步驟,具體可以有兩種辦法:內(nèi)存塊2先于3分配,這樣3釋放后自然同1連在一起。內(nèi)存塊2在3釋放之后再分配,這樣2占了內(nèi)存3的位置,剩余的內(nèi)存也是連續(xù)的。具體用什么方法,就要根據(jù)實際的具體情況,看哪一種方法是最可行的。在客戶的這個問題中,內(nèi)存塊3是一個第三方桌面插件分配的,內(nèi)存塊2是QQ分配的。所以第2種方法最可行,在分配QQ的內(nèi)存前,先釋放掉第三方桌面插件的內(nèi)存,問題由此解決。.512022/12/19MOCOR內(nèi)存bug實例分析注意:并不是所有的內(nèi)存碎片問題都能夠通過這樣的調(diào)整來得到解決。系統(tǒng)運行的過程中,一些內(nèi)存碎片的產(chǎn)生是無法避免的,這種情況下內(nèi)存碎片無法得到消除或消除的難度很大。.522022/12/19MOCOR內(nèi)存bug實例分析3.實際內(nèi)存不足:如果出現(xiàn)剩余的內(nèi)存不夠分配,此時查看內(nèi)存分配的情況也沒有異常(也就是說已經(jīng)排除了內(nèi)存泄露和碎片的原因),這種情況就是真正的內(nèi)存不足了。遇到這種情況,一般有這些思路:要求客戶裁剪功能,減少內(nèi)存的使用,通??蛻魰ζ脚_版本進行一些定制,比如增加一些第三方應(yīng)用等等,這些新增的模塊往往會造成內(nèi)存使用的增加。如果某些操作很耗內(nèi)存,那么執(zhí)行這些操作時最好將其他操作退出,盡量避免并發(fā)。以上都不行的話最后只能通過增大heapsize來解決。.532022/12/19MOCOR內(nèi)存bug實例分析某客戶上報問題,進文件管理器,選擇一張gif圖片發(fā)彩信時出現(xiàn)內(nèi)存不足死機:File:RTOS\source\src\c\threadx_mem.cLine:494ASSERT(ASSERT:Error0x10(Nomemory,unabletoallocate!),block_mem.c,line=521,param=0x25804)從上面的信息可以看到欲分配的內(nèi)存大小是0x25804(153604)。查看appheap的使用情況如下.542022/12/19MOCOR內(nèi)存bug實例分析.552022/12/19MOCOR內(nèi)存bug實例分析
可以看到當(dāng)前剩余的總內(nèi)存也不過是141744,其中最大一塊空閑內(nèi)存是0x1aa4c(109132),還差0x25804-0x1aa4c=0xADB8(44472)才夠分配。我們用剛才的幾種思路分析一下:裁剪功能,因為沒有第三方的東西,這個不考慮避免并發(fā)。通過分析內(nèi)存,可以看到分配的內(nèi)存實際上可以分為兩大塊(見上圖),一塊是上面紅框的部分,主要是由FMM分配的。另一塊是下面紅框部分,主要是由MMS分配,所以這里存在MMS和FMM并發(fā)的情況。如果我們在發(fā)送彩信之前就先退出FMM的話,可以解決此問題。增大heap。前面我們已經(jīng)算出當(dāng)前差了44472字節(jié),修改mem_cfg.c,將appheap的大小增加至少44K。需要注意的是,如果要增大heap,首先要確認一下當(dāng)然ram是否還有這么多可用的空間,可以通過查看map文件最后的幾行信息:
TotalROSize(Code+ROData)7530419(7353.92kB)TotalRWSize(RWData+ZIData)3944375(3851.93kB)TotalROMSize(Code+ROData+RWData)7586078(7408.28kB)
紅色的RWsize就是我們要關(guān)注的,可以看到當(dāng)前RW使用了3851K,而RAM的總數(shù)是4096K,所以還有充足的空間,heap增加個幾十K沒有什么問題。可以看到使用2和3都可以解決問題,通常把增大heap作為最后的手段。.562022/12/19MOCOR內(nèi)存bug實例分析內(nèi)存覆蓋:內(nèi)存覆蓋也是常見的一類內(nèi)存問題,引起內(nèi)存覆蓋的原因很多,往往沒有固定規(guī)律可循。而且有時出現(xiàn)覆蓋后并不立刻死機,這樣無法確認第一現(xiàn)場,增大了解決問題的難度。但在MOCOR平臺下,我們有一個非常有用的工具:BusMonitor。利用BusMonitor(后文簡稱BM),我們有一個解決覆蓋問題的一般性思路:首先確定被覆蓋內(nèi)存的地址(可能是一個地址范圍),如果問題可以重現(xiàn),且每次被覆蓋的地址比較固定,則可以用BM監(jiān)控被覆蓋的地址,這樣當(dāng)內(nèi)存被覆蓋時會第一時間死機,可以迅速定位。BusMonitor的用法比較簡單,可以參考相關(guān)文檔。.572022/12/19MOCOR內(nèi)存bug實例分析1.案例一內(nèi)存寫入時越界是出現(xiàn)內(nèi)存覆蓋的一個常見原因,相對來說也比較好查的,只要找到越界的那塊內(nèi)存基本就可以定位,我們看下面的例子:客戶項目發(fā)現(xiàn)進入電話本偶而會出現(xiàn)死機,死機現(xiàn)場:File:RTOS\source\src\c\threadx_mem.cLine:364ASSERT(ASSERT:Error0x10(Nomemory,unabletoallocate!),wdp_customer.c,line=2098,param=0xFA4)初一看好像是個內(nèi)存不足的,但實際不是,assert界面輸入4后打出當(dāng)前分配的內(nèi)存,就會發(fā)現(xiàn)有錯誤:.582022/12/19MOCOR內(nèi)存bug實例分析.592022/12/19MOCOR內(nèi)存bug實例分析
可以看到最后一行“memoryiscorrupted”,表明在遍歷memheader的鏈表時出錯,這意味著某一塊memory的header異常了,而且這塊內(nèi)存的地址是0x40bcc3
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 企業(yè)級數(shù)據(jù)安全合規(guī)策略制定服務(wù)協(xié)議
- 四川省成都市武侯區(qū)2024-2025學(xué)年七年級上學(xué)期期末生物學(xué)試題(含答案)
- 湖南省岳陽市岳陽縣2024-2025學(xué)年七年級上學(xué)期期末生物學(xué)試題(含答案)
- 濕地松采脂承包合同
- 暗井澆筑工程 現(xiàn)場質(zhì)量檢驗報告單
- 紅外相機知識培訓(xùn)課件
- 寵物美容服務(wù)寵物行為問題處理協(xié)議
- 人力資源外包服務(wù)協(xié)議條款及簽訂注意事項
- 血管是血液流動的管道課件-2024-2025學(xué)年北師大版七年級下冊
- 電子產(chǎn)品生產(chǎn)加工承攬合同
- 現(xiàn)代家政導(dǎo)論-課件 2.1家庭的認知
- 護理相關(guān)法律法規(guī)
- 2024中國移動公司招聘高頻500題難、易錯點模擬試題附帶答案詳解
- 江蘇省宿遷市2024年中考數(shù)學(xué)試卷含答案
- 河道綜合治理工程施工組織設(shè)計(投標)
- 處方書寫規(guī)范考核試題及答案
- 餐飲配方傳授合同范本
- 22G101三維彩色立體圖集
- 福建省教師公開招聘考試(小學(xué)數(shù)學(xué))模擬試卷1(共236題)
- 順豐快遞員工入職合同范本
- 《智慧農(nóng)業(yè)》教學(xué)課件
評論
0/150
提交評論