qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問 http://qaseven.github.io/

          linux內(nèi)存分配方法總結(jié)

           內(nèi)存映射結(jié)構(gòu):

            1、32位地址線尋址4G的內(nèi)存空間,其中0-3G為用戶程序所獨(dú)有,3G-4G為內(nèi)核占有。

            2、struct page:整個(gè)物理內(nèi)存在初始化時(shí),每個(gè)4kb頁(yè)面生成一個(gè)對(duì)應(yīng)的struct page結(jié)構(gòu),這個(gè)page結(jié)構(gòu)就獨(dú)一無(wú)二的代表這個(gè)物理內(nèi)存頁(yè)面,并存放在mem_map全局?jǐn)?shù)組中。

            3、段式映射:首先根據(jù)代碼段選擇子cs為索引,以GDT值為起始地址的段描述表中選擇出對(duì)應(yīng)的段描述符,隨后根據(jù)段描述符的基址,本段長(zhǎng)度,權(quán)限信息等進(jìn)行校驗(yàn),校驗(yàn)成功后。cs:offset中的32位偏移量直接與本段基址相累加,得出最終訪問地址。

            0-3G與mem_map的映射方式:

            因linux中采用的段式映射為flat模式,所以從邏輯地址到線性地址沒有變化。從段式出來進(jìn)入頁(yè)式,每個(gè)用戶進(jìn)程都獨(dú)自擁有一個(gè)頁(yè)目錄表 (pdt),運(yùn)行時(shí)存放于CR3。  CR3(頁(yè)目錄) + 前10位 =>  頁(yè)面表基址 + 中10位 => 頁(yè)表項(xiàng) + 后12位 => 物理頁(yè)面地址

            3G-4G與mem_map的映射方式:

            分為三種類型:低端內(nèi)存/普通內(nèi)存/高端內(nèi)存。

            低端內(nèi)存:3G-3G+16M 用于DMA        __pa線性映射

            普通內(nèi)存:3G+16M-3G+896M           __pa線性映射 (若物理內(nèi)存<896M,則分界點(diǎn)就在3G+實(shí)際內(nèi)存)

            高端內(nèi)存:3G+896-4G                采用動(dòng)態(tài)的分配方式

            4、高端內(nèi)存(假設(shè)3G+896為高端內(nèi)存起址)

            作用:訪問到1G以外的物理內(nèi)存空間。

            線性地址共分為三段:vmalloc段/kmap段/kmap_atomic段(針對(duì)與不同的內(nèi)存分配方式)

            從內(nèi)存分配函數(shù)的結(jié)構(gòu)來看主要分為下面幾個(gè)部分:

            a.伙伴算法(最原始的面向頁(yè)的分配方式)

            alloc_pages 接口:

            struct page * alloc_page(unsigned int gfp_mask)--分配一頁(yè)物理內(nèi)存并返回該頁(yè)物理內(nèi)存的page結(jié)構(gòu)指針。

            struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)--分配 個(gè)連續(xù)的物理頁(yè)并返回分配的第一個(gè)物理頁(yè)的page結(jié)構(gòu)指針。

            <釋放函數(shù):__free_page(s)>

            內(nèi)核中定義:#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)

            最終都是調(diào)用 __alloc_pages.

            其中MAX_ORDER 11,及最大分配到到頁(yè)面?zhèn)€數(shù)為2^10(即4M)。

            分配頁(yè)后還不能直接用,需要得到該頁(yè)對(duì)應(yīng)的虛擬地址:

            void *page_address(struct page *page);

            低端內(nèi)存的映射方式:__va((unsigned long)(page  -  mem_map)  <<  12)

            高端內(nèi)存到映射方式:struct page_address_map分配一個(gè)動(dòng)態(tài)結(jié)構(gòu)來管理高端內(nèi)存。(內(nèi)核是訪問不到vma的3G以下的虛擬地址的) 具體映射由kmap / kmap_atomic執(zhí)行。

            get_free_page接口:(alloc_pages接口兩步的替代函數(shù))

            unsigned long get_free_page(unsigned int gfp_mask)

            unsigned long __get_free_page(unsigned int gfp_mask)

            Unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order)

            <釋放函數(shù):free_page>

            與alloc_page(s)系列最大的區(qū)別是無(wú)法申請(qǐng)高端內(nèi)存,因?yàn)樗祷氐绞且粋€(gè)線性地址,而高端內(nèi)存是需要額外映射才可以訪問的。

           b.slab高速緩存(反復(fù)分配很多同一大小內(nèi)存)   注:使用較少

            kmem_cache_t* xx_cache;

            創(chuàng)建: xx_cache = kmem_cache_create(“name”, sizeof(struct xx), SLAB_HWCACHE_ALIGN, NULL, NULL);

            分配: kmem_cache_alloc(xx_cache, GFP_KERNEL);

            釋放: kmem_cache_free(xx_cache, addr);

            內(nèi)存池

            mempool 不使用。

            c.kmalloc(最常用的分配接口)         注:必須小于128KB

            GFP_ATOMIC 不休眠,用于中斷處理等情況

            GFP_KERNEL 會(huì)休眠,一般狀況使用此標(biāo)記

            GFP_USER   會(huì)休眠

            __GFP_DMA  分配DMA內(nèi)存

            kmalloc/kfree

            d.vmalloc/vfree

            vmalloc采用高端內(nèi)存預(yù)留的虛擬空間來收集內(nèi)存碎片引起的不連續(xù)的物理內(nèi)存頁(yè),是用于非連續(xù)物理內(nèi)存分配。

            當(dāng)kmalloc分配不到內(nèi)存且無(wú)物理內(nèi)存連續(xù)的需求時(shí),可以使用。(優(yōu)先從高端內(nèi)存中查找)

            e.ioremap()/iounmap()

            ioremap()的作用是把device寄存器和內(nèi)存的物理地址區(qū)域映射到內(nèi)核虛擬區(qū)域,返回值為內(nèi)核的虛擬地址。使用的線性地址區(qū)間也在vmmlloc段

            注:

            vmalloc()與 alloc_pages(_GFP_HIGHMEM)+kmap();前者不連續(xù),后者只能映射一個(gè)高端內(nèi)存頁(yè)面

            __get_free_pages與alloc_pages(NORMAL)+page_address(); 兩者完全等同

            內(nèi)核地址通過 __va/__pa進(jìn)行中低內(nèi)存的直接映射

            高端內(nèi)存采用kmap/kmap_atomic的方式來映射

            個(gè)人總結(jié)如下:

            a.在<128kB的一般內(nèi)存分配時(shí),使用kmalloc

            允許睡眠:GFP_KERNEL

            不允許睡眠:GFP_ATOMIC

            b.在>128kB的內(nèi)存分配時(shí),使用get_free_pages,獲取成片頁(yè)面,直接返回虛擬地址(<4M)(或alloc_pages + page_address)

            c.b失敗,

            如果要求分配高端內(nèi)存:alloc_pages(_GFP_HIGHMEM)+kmap(僅能映射一個(gè)頁(yè)面)

            如果不要求內(nèi)存連續(xù): 則使用vmalloc進(jìn)行分配邏輯連續(xù)的大塊頁(yè)面.(不建議)/分配速度較慢,訪問速率較慢。

            d.頻繁創(chuàng)建和銷毀很多較大數(shù)據(jù)結(jié)構(gòu),使用slab.

            e.高端內(nèi)存映射:

            允許睡眠:kmap              (永久映射)

            不允許睡眠:kmap_atomic      (臨時(shí)映射)會(huì)覆蓋以前到映射(不建議)

          posted on 2013-05-22 10:05 順其自然EVO 閱讀(1760) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2013年5月>
          2829301234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 柯坪县| 乌海市| 科技| 兴国县| 龙门县| 万年县| 石家庄市| 昭通市| 五常市| 安阳市| 天柱县| 楚雄市| 沙雅县| 息烽县| 马尔康县| 麻栗坡县| 财经| 东乌| 天等县| 古丈县| 内黄县| 黎城县| 洛扎县| 郴州市| 文安县| 温宿县| 湘乡市| 兰西县| 蒲城县| 常熟市| 防城港市| 大同市| 临朐县| 博湖县| 毕节市| 乌鲁木齐县| 西乌| 宽城| 探索| 金平| 云林县|