亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        VxWorks系統(tǒng)中內(nèi)存池的應(yīng)用

        2018-10-13 02:45:26安景新趙昶宇
        科技與創(chuàng)新 2018年19期
        關(guān)鍵詞:鏈表空閑字節(jié)

        安景新,趙昶宇

        VxWorks系統(tǒng)中內(nèi)存池的應(yīng)用

        安景新1,趙昶宇2

        (1.海軍駐天津八三五七所軍事代表室,天津 300308;2.天津津航計算技術(shù)研究所,天津 300308)

        針對嵌入式軟件內(nèi)存管理具有快速性、可靠性和高效性的特點,分析了VxWorks內(nèi)存管理機制,闡述了內(nèi)存池結(jié)構(gòu)和工作原理,深入剖析了內(nèi)存池的分配和釋放機制,并對VxWorks系統(tǒng)下的內(nèi)存管理提出了建議。

        嵌入式系統(tǒng);VxWorks;內(nèi)存管理;內(nèi)存池

        利用默認(rèn)的內(nèi)存管理函數(shù)new/delete或malloc/free在堆上分配和釋放內(nèi)存會有一些額外的開銷。如果應(yīng)用程序頻繁地在堆上分配和釋放內(nèi)存,則會導(dǎo)致性能的降低,并且會使系統(tǒng)中出現(xiàn)大量的內(nèi)存碎片,降低內(nèi)存的利用率。

        經(jīng)典的內(nèi)存池(MemPool)技術(shù)是一種用于分配大量大小相同的小對象的技術(shù)。該技術(shù)可以極大地加快內(nèi)存分配/釋放過程。如果合理地規(guī)劃內(nèi)存池的大小以及數(shù)量,可以減少動態(tài)分配、釋放內(nèi)存時的消耗,并且可以有效減少內(nèi)存碎片,避免內(nèi)存泄漏。

        本文以VxWorks操作系統(tǒng)為例,重點分析了內(nèi)存池管理機制,并對內(nèi)存分配和釋放給出了解決方案。

        1 VxWorks內(nèi)存管理機制

        VxWorks采用用戶程序、內(nèi)核處于同一個地址空間的內(nèi)存管理策略,軟件開發(fā)人員在開發(fā)程序時必須保證不侵犯其他程序和內(nèi)核的地址空間,以免破壞系統(tǒng)的正常工作,或?qū)е缕渌绦虍惓_\行。內(nèi)核負(fù)責(zé)為程序分配內(nèi)存、動態(tài)分配內(nèi)存和回收內(nèi)存。VxWorks為用戶提供2種內(nèi)存區(qū)域,即內(nèi)存域region和內(nèi)存分區(qū)partition.region是可變長的內(nèi)存區(qū),可以從創(chuàng)建的region中再分配段segment,region的特點是容易產(chǎn)生碎片,但靈活、不浪費;partition是定長的內(nèi)存區(qū),用戶可以從創(chuàng)建的partition中分配內(nèi)存塊,或在某個內(nèi)存分區(qū)中再創(chuàng)建一個內(nèi)存分區(qū)。

        partition的特點是無碎片、效率高,但存在浪費。通常情況下,VxWorks內(nèi)核和應(yīng)用程序?qū)?nèi)存的操作是基于內(nèi)存分區(qū)進行的。內(nèi)存池是一塊連續(xù)的內(nèi)存區(qū)域,包含1個或多個內(nèi)存塊。內(nèi)存分區(qū)包含分區(qū)自身的描述信息(1個結(jié)構(gòu)體)和1個或多個內(nèi)存池,描述信息保存在系統(tǒng)內(nèi)存分區(qū)中,內(nèi)存池是該分區(qū)實際擁有的內(nèi)存空間。內(nèi)存分區(qū)剛創(chuàng)建完畢時,只有1個內(nèi)存池,以后用戶程序可往該分區(qū)中添加內(nèi)存池。內(nèi)存池之間的地址不一定連續(xù),VxWorks在啟動過程中會創(chuàng)建一個包含系統(tǒng)內(nèi)存池的系統(tǒng)內(nèi)存分區(qū),如圖1所示。

        圖1 VxWorks的內(nèi)存布局

        2 基于內(nèi)存池的內(nèi)存分配方案

        應(yīng)用程序可以通過系統(tǒng)的內(nèi)存分配調(diào)用預(yù)先一次性申請適當(dāng)大小的內(nèi)存作為1個內(nèi)存池,之后應(yīng)用程序?qū)?nèi)存的分配和釋放則可以通過內(nèi)存池來完成。內(nèi)存池技術(shù)申請內(nèi)存/釋放內(nèi)存均極其快,其內(nèi)存分配過程多數(shù)情況下復(fù)雜度為O(1),內(nèi)存釋放過程復(fù)雜度為O(1)。主要開銷在生成新的空閑內(nèi)存單元。

        2.1 內(nèi)存池結(jié)構(gòu)

        內(nèi)存池的結(jié)構(gòu)如圖2所示。

        定義內(nèi)存池控制塊T_MemoryPool數(shù)據(jù)結(jié)構(gòu)如下:

        Typedef struct MemoryPool{

        MemoryBlock* pBlock; /* 第一個block 的指針 */

        Unsigned short nUnitSize; /* 每個小內(nèi)存塊的字節(jié)數(shù) */

        Unsigned short nInitSize; /* 初始的Block 的內(nèi)存塊數(shù)目 */

        Unsigned short nGrowSize; /* 增加的Block 的內(nèi)存塊數(shù)目 */

        }T_MemoryPool;

        定義內(nèi)存塊T_MemoryBlock數(shù)據(jù)結(jié)構(gòu)如下:

        Typedef struct MemoryBlock{

        Unsigned short nSize; /* 內(nèi)存塊的大小 */

        Unsigned short nFree; /* 空閑塊數(shù) */

        Unsigned short nFirst; /* 第一個空閑塊 */

        MemoryBlock* pNext; /* 下一個Block */

        char aData[1]; /* 數(shù)據(jù)的初始位置 */

        }T_MemoryBlock;

        圖2 內(nèi)存池結(jié)構(gòu)

        2.2 內(nèi)存池工作原理

        在運行過程中,MemoryPool內(nèi)存池可能會有多個用來滿足內(nèi)存申請請求的內(nèi)存塊,這些內(nèi)存塊是從進程堆中開辟的一個較大的連續(xù)內(nèi)存區(qū)域,它由一個MemoryBlock結(jié)構(gòu)體和多個可供分配的空閑內(nèi)存單元組成,所有內(nèi)存塊組成了一個內(nèi)存塊鏈表,MemoryPool的pBlock是這個鏈表的頭。對每個內(nèi)存塊,都可以通過其頭部的MemoryBlock結(jié)構(gòu)體的pNext成員訪問緊跟在其后面的內(nèi)存塊。

        每個內(nèi)存塊由2部分組成,即1個MemoryBlock結(jié)構(gòu)體和多個內(nèi)存分配單元。這些內(nèi)存分配單元大小固定(由MemoryPool的nUnitSize表示),MemoryBlock結(jié)構(gòu)體有2個成員比較重要,即nFree和nFirst.

        nFree記錄這個內(nèi)存塊中還有多少個空閑單元,而nFirst則記錄下一個空閑單元的編號。每一個空閑單元的前兩個字節(jié)記錄了緊跟它之后的下一個空閑單元的編號。在此情況下,通過利用每個空閑單元的前兩個字節(jié),一個MemoryBlock中的所有空閑單元被連接起來。

        當(dāng)有新的內(nèi)存請求到來時,MemoryPool會通過pBlock遍歷MemoryBlock鏈表,直到找到某個MemoryBlock所在的內(nèi)存塊,及其中的空閑單元(通過檢測MemoryBlock結(jié)構(gòu)體的nFree 成員是否大于0)。如果找到這樣的內(nèi)存塊,取得其MemoryBlock的nFirst值(此為該內(nèi)存塊中第一個空閑單元的編號),則根據(jù)這個編號定位到該空閑單元的起始位置(所有單元大小固定,因此,每個單元的起始位置都可以通過編號分配單元大小來偏移定位),這個位置就是用來滿足此次內(nèi)存申請請求的內(nèi)存起始地址。但在返回這個地址前,需要先將該位置開始的前兩個字節(jié)的值(這兩個字節(jié)值記錄其之后的下一個空閑單元的編號)賦給本內(nèi)存塊的MemoryBlock的nFirst成員。在此情況下,下一次的請求就可被這個編號對應(yīng)的內(nèi)存單元來滿足,同時,將此內(nèi)存塊的MemoryBlock的nFree遞減1,然后將定位到的內(nèi)存單元的起始位置作為此次內(nèi)存請求的返回地址返回給調(diào)用者。

        如果從現(xiàn)有的內(nèi)存塊中找不到一個自由的內(nèi)存分配單元(當(dāng)?shù)谝淮握埱髢?nèi)存以及現(xiàn)有的所有內(nèi)存塊中的內(nèi)存單元都已經(jīng)被分配時,會發(fā)生這種情況),MemoryPool就會從進程堆中申請1個內(nèi)存塊。

        當(dāng)某個被分配的單元因free操作需要回收時,該單元并不會返回給進程堆,而是返回給MemoryPool。返回時,MemoryPool能獲取該單元的起始地址。此時,MemoryPool開始遍歷其所維護的內(nèi)存塊鏈表,判斷該單元的起始地址是否落在某個內(nèi)存塊的地址范圍內(nèi)。如果不在所有內(nèi)存地址的范圍內(nèi),則此被回收的單元不屬于這個MemoryPool,將整個內(nèi)存塊返回給內(nèi)存堆;如果在某個內(nèi)存塊的地址范圍內(nèi),則它會將剛剛回收的分配單元加到這個內(nèi)存塊的MemoryBlock所維護的空閑單元鏈表頭部。

        2.3 內(nèi)存分配機制

        進行內(nèi)存分配前,先判斷內(nèi)存池當(dāng)前內(nèi)存塊鏈表是否為空。如果為空,則意味著這是第一次內(nèi)存申請請求。此時,從進程堆中申請一個分配單元個數(shù)為nInitSize的內(nèi)存塊,并初始化該內(nèi)存塊。初始化的操作包括設(shè)置MemoryBlock的nSize為所有內(nèi)存分配單元的大小、nFree為-1、nFirst為1,并將編號為0的分配單元之后的所有空閑單元連接起來,即從aData位置開始,每隔nUnitSize大小取其最前面的兩個字節(jié),并記錄之后空閑單元的編號。

        如果該內(nèi)存塊申請成功,并初始化完畢,返回第一個分配單元給調(diào)用函數(shù)。第一個分配單元以MemoryBlock結(jié)構(gòu)體內(nèi)的最后一個字節(jié)為起始地址。

        當(dāng)內(nèi)存池中已有內(nèi)存塊時,遍歷該內(nèi)存塊鏈表,尋找有空閑單元的內(nèi)存塊。如果找到有空閑單元的內(nèi)存塊,則“定位”該內(nèi)存塊為可用的空閑單元處,“定位”以MemoryBlock結(jié)構(gòu)體內(nèi)的最后一個字節(jié)位置aData為起始位置,以MemoryPool的nUnitSize為步長來進行;修改MemoryBlock nFree信息,以及修改此內(nèi)存塊的空閑單元鏈表信息。在找到的內(nèi)存塊中,nFirst為該內(nèi)存塊中自由存儲單元鏈表的表頭,其下一個空閑單元的編號存放在nFirst指示的空閑單元的前兩個字節(jié)。通過定位得到的位置,取其前兩個字節(jié)的值賦給nFirst,這就是此內(nèi)存塊空閑單元鏈表的新表頭,即下一次分配的空閑單元的編號。

        如果沒有找到有空閑單元的內(nèi)存塊,則需要重新向進程堆申請一個內(nèi)存塊。此時,由于不是第一次申請內(nèi)存塊,所以,申請的內(nèi)存塊包含的分配單元個數(shù)為nGrowSize,而不再是nInitSize。初始化這個新申請的內(nèi)存塊,并將此內(nèi)存塊插入MemoryPool的內(nèi)存塊鏈表的頭部,再將此內(nèi)存塊的第一個分配單元返回給調(diào)用函數(shù)。將此新內(nèi)存塊插入內(nèi)存塊鏈表頭部的原因是該內(nèi)存塊還有很多可供分配的空閑單元,放在頭部可以使下次接收到內(nèi)存申請時,減少對內(nèi)存塊的遍歷時間。

        2.4 內(nèi)存釋放機制

        遍歷內(nèi)存池的內(nèi)存塊鏈表,確定該待回收分配單元(pFree)落在哪一個內(nèi)存塊的指針范圍內(nèi),可通過比較指針值來確定。找到的包含pFree所指向的待回收分配單元的內(nèi)存塊后,修改該內(nèi)存塊的空閑單元鏈表信息,將這個待回收分配單元的前兩個字節(jié)的值指向該內(nèi)存塊原先的第一個可分配的空閑單元的編號,并將nFirst值改變?yōu)橹赶蜻@個待回收分配單元的編號,該操作將待回收分配單元放在了空閑單元鏈表的頭部。需要注意的是,該單元的內(nèi)存地址并沒有改變,改變的只是其狀態(tài)(已分配/空閑),以及當(dāng)其處于空閑狀態(tài)時在空閑單元鏈表中的位置。

        回收后,考慮到資源的有效利用及后續(xù)操作的性能,內(nèi)存池的操作會繼續(xù)判斷:如果此內(nèi)存塊所有分配單元都是空閑的,則這個內(nèi)存塊就會從MemoryPool中被移出,并作為一個整體返回給進程堆;如果該內(nèi)存塊中還有非空閑單元,則不將此內(nèi)存塊返回給進程堆。但是因為剛剛有一個分配單元返回給了這個內(nèi)存塊,即這個內(nèi)存塊有空閑單元可供下次分配,則它會被移到MemoryPool維護的內(nèi)存塊的頭部。在此情況下,內(nèi)存請求到來,MemoryPool遍歷其內(nèi)存塊鏈表尋找空閑單元時,第一次尋找就會找到這個內(nèi)存塊。因為這個內(nèi)存塊確實有空閑單元,這樣可以減少MemoryPool的遍歷次數(shù)。

        3 問題和建議

        在使用內(nèi)存池機制管理內(nèi)存時,需要注意以下幾點:①判斷內(nèi)存塊的所有單元是否都處于空閑狀態(tài)時,不用遍歷其所有單元,只需要判斷nFree乘以nUnitSize是否等于nSize、nSize內(nèi)存塊中所有分配單元的大?。ú话^部MemoryBlock結(jié)構(gòu)體的大小),這樣可快速檢查某個內(nèi)存塊中所有分配單元是否全部處于空閑狀態(tài)。②不能通過比較nFree與nInitSize或nGrowSize的大小來判斷某個內(nèi)存塊中所有分配單元都為空閑狀態(tài),這是因為第一次分配的內(nèi)存塊(分配單元個數(shù)為nInitSize)可能被移到鏈表的后面,甚至有可能在移動到鏈表后面之后,因為某個時間其所有單元都處于空閑狀態(tài)而被整個返回給進程堆,即在回收分配單元時,無法判定某個內(nèi)存塊中的分配單元個數(shù)是nInitSize還是nGrowSize,也就無法通過比較nFree與nInitSize或nGrowSize的大小,來判斷內(nèi)存塊的所有分配單元是否都為空閑狀態(tài)。③在進行內(nèi)存釋放操作后,雖然pFree被“回收”,但是pFree仍然指向當(dāng)前已“回收”的單元,這個單元在回收過程中,其前兩個字節(jié)被覆寫,但其他部分的內(nèi)容并沒有改變。且從整個進程的內(nèi)存使用角度看,該“回收”的單元的狀態(tài)仍然是“有效的”。因為這里的“回收”只是回收給了內(nèi)存池,而并沒有回收給進程堆,因此,程序仍然可以通過pFree訪問此單元。但這是一個很危險的操作,因為該單元在回收過程中的前兩個字節(jié)已被覆寫,且該單元可能很快會被內(nèi)存池重新分配。因此,回收后通過pFree指針對這個單元的訪問都是錯誤的,讀操作會讀到錯誤的數(shù)據(jù),寫操作則可能會破壞程序中的其他數(shù)據(jù),需要注意此問題。

        4 結(jié)束語

        內(nèi)存的申請和釋放對一個應(yīng)用程序的整體性能影響極大,甚至在很多時候會成為某個應(yīng)用程序的瓶頸。消除內(nèi)存申請和釋放瓶頸的方法往往是針對內(nèi)存使用的實際情況,提供合適的內(nèi)存池。通過性能測試表明,內(nèi)存池具有malloc/free進行內(nèi)存申請/釋放的方式快、不會產(chǎn)生或很少產(chǎn)生堆碎片、可避免內(nèi)存泄漏等明顯特性。以上所描述的基于內(nèi)存池的內(nèi)存管理方法具有很大的實用價值,希望能給嵌入式軟件工作者啟發(fā),從而設(shè)計出更好的內(nèi)存管理方法。

        [1]顧勝元,楊丹,黃海倫.嵌入式實時動態(tài)內(nèi)存管理機制研究與應(yīng)用[J].重慶工學(xué)院學(xué)報(自然科學(xué)),2009(01): 117-121.

        [2]許健,于鴻洋.一種Linux多線程應(yīng)用下內(nèi)存池的設(shè)計與實現(xiàn)[J].電子技術(shù)應(yīng)用,2012,38(11):146-149.

        [3]何煦嵐,何曉嵐.基于多鏈表結(jié)構(gòu)的嵌入式系統(tǒng)內(nèi)存管理[J].計算機應(yīng)用與軟件,2008,25(04):58-60.

        〔編輯:張思楠〕

        2095-6835(2018)19-0145-03

        TP316.2

        A

        10.15913/j.cnki.kjycx.2018.19.145

        安景新(1990—),男,工學(xué)碩士,助理工程師,從事裝備質(zhì)量監(jiān)督與檢驗驗收方面的工作與研究。趙昶宇(1982—),男,陜西漢中人,工學(xué)碩士,高級工程師,主要從事嵌入式系統(tǒng)軟件測試方面的研究。

        猜你喜歡
        鏈表空閑字節(jié)
        恩賜
        詩選刊(2023年7期)2023-07-21 07:03:38
        No.8 字節(jié)跳動將推出獨立出口電商APP
        “鳥”字謎
        小讀者之友(2019年9期)2019-09-10 07:22:44
        基于二進制鏈表的粗糙集屬性約簡
        No.10 “字節(jié)跳動手機”要來了?
        跟麥咭學(xué)編程
        基于鏈表多分支路徑樹的云存儲數(shù)據(jù)完整性驗證機制
        彪悍的“寵”生,不需要解釋
        簡談MC7字節(jié)碼
        WLAN和LTE交通規(guī)則
        CHIP新電腦(2016年3期)2016-03-10 14:09:48
        国产日产精品久久久久久| 精品国产一区二区三区久久女人| 日本熟妇中文字幕三级| 综合激情五月三开心五月| 欧美牲交a欧美牲交aⅴ免费下载 | 亚洲成a人片在线观看导航| 伊人久久综合狼伊人久久| 亚洲中文久久精品字幕| 日韩精品久久久肉伦网站| 狠狠色狠狠色综合| 日本久久精品在线播放| 国产av一区二区亚洲精品| 国产后入又长又硬| 亚洲成人福利在线观看| 精品少妇人妻久久免费| 亚洲一区二区三区蜜桃| 女人喷潮完整视频| 国产成人无码A区在线观| 国内激情一区二区视频| 狠狠综合亚洲综合亚洲色 | 国产自精品| 天堂av中文在线官网| 日本饥渴人妻欲求不满| 日日噜噜噜夜夜爽爽狠狠视频| 色婷婷久久一区二区三区麻豆| 91久久国产自产拍夜夜嗨| 精品日韩在线观看视频| 国产精品天干天干| 又黄又爽又色又刺激的视频| caoporon国产超碰公开| 日韩有码在线观看视频| 小鲜肉自慰网站| 欧美日韩亚洲成色二本道三区 | 一本色道久久88综合日韩精品| 91国际视频| 女同另类一区二区三区| 国产成人av在线免播放观看新| 国产女主播精品大秀系列| 热久久这里只有| 免费看黄片视频在线观看| 又黄又爽又无遮挡免费的网站|