亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Linux Kernel啟動(dòng)過程中的內(nèi)存管理

系統(tǒng) 2231 0

?

原文地址:http://blog.csdn.net/ariesjzj/article/details/8764102

好的操作系統(tǒng)必然要有好的內(nèi)存管理系統(tǒng)來支持。好的內(nèi)存管理系統(tǒng)就像一個(gè)藝術(shù)品,因?yàn)樵谄渲形覀兛梢钥吹娇臻g優(yōu)化和時(shí)間優(yōu)化的完美平衡(既要省內(nèi)存又要分配和釋放足夠快)。Linux為我們提供了這樣一個(gè)范例,關(guān)于它的內(nèi)存管理在很多講kernel的書都可以找到。但在這一切還沒有建立起來時(shí),系統(tǒng)又是怎么工作的呢?


在系統(tǒng)啟動(dòng)時(shí)內(nèi)存分配大致經(jīng)歷了這樣幾個(gè)階段(基于kernel 2.6.29):

1. 靜態(tài)分配(如果這也算一種的話。。。)
2. e820表
3. bootmem allocator
4. zone allocator(buddy system)
5. slab allocator
6. 虛擬空間分配,如用vmalloc, mmap這些函數(shù)分配

當(dāng)然以上的幾個(gè)階段的時(shí)間界限并不總是很明顯,有些時(shí)候是并存的。以下是初始化代碼中幾個(gè)關(guān)鍵點(diǎn):

    start_kernel()

	setup_arch()

	setup_memory_map() //從boot_params.e820_map讀入e820表信息,以后就可以用find_e820_area()分配了。

	init_memory_mapping()

		kernel_physical_mapping_init() //在虛擬空間映射kernel頁(yè)表的low mem部分,創(chuàng)建頁(yè)表過程中需要分配內(nèi)存就是通過find_e820_area()。

	initmem_init()  

		setup_bootmem_allocator() //初始化bootmem allocator,bootmem allocator可用。

			early_res_to_bootmem() //把之前靜態(tài)分配或者從通過find_e820_area()分配的區(qū)域置成保留。

	paging_init() //完成kernel頁(yè)表high mem中persistent kernel mapping和temporary kernel mapping部分的初始化,之后可以通過kmap()或kmap_atomic()把物理頁(yè)映射到high mem區(qū)域。

		zone_sizes_init() //初始化zone allocator,但只是初始化,還沒法用它分配,因?yàn)樗械膄reelist還是被置成空的。

vmalloc_init() //初始化分配noncontiguous memory area所需要的結(jié)構(gòu)。vmalloc能分配high mem中從VMALLOC_START到VMALLOC_END的虛擬空間。加上前面paging_init()中提到的兩種,針對(duì)kernel的high mem的三種映射方式就全了。該函數(shù)中通過bootmem allocator分配自身需要的內(nèi)存。

mem_init() //完成zone allocator,也就是buddy system的初始化,之后alloc_page()就可以用了。這里將bootmem allocator中的未分配空間轉(zhuǎn)到zone allocator中,然后禁用了bootmem allocator。

kmem_cache_init() //初始化slab allocator。它是zone allocator上的一層加強(qiáng),彌補(bǔ)了zone allocator的一些固有不足,如只能以2的n次冪分配物理頁(yè)。kmalloc()會(huì)從slab allocator上分配,而slab allocator中cache不夠又會(huì)從zone allocator分配。
  

?


系統(tǒng)啟動(dòng)剛開始的一些數(shù)據(jù)是靜態(tài)分配的,如kernel本身的代碼段和數(shù)據(jù)段,因?yàn)檫@時(shí)還沒有任何分配器存在。這些都被loader存放在固定的物理地址,并被臨時(shí)頁(yè)表映射到固定的虛擬地址。

e280表和find_e820_area()可以稱得上最早的allocator,盡管它很簡(jiǎn)單。系統(tǒng)啟動(dòng)早期,detect_memory()函數(shù)中,系統(tǒng)通過15h中斷從BIOS中讀取物理內(nèi)存信息,將之放到boot_params(也就是zeropage中)。之后set_memory_map()函數(shù)將這些信息再讀入e820結(jié)構(gòu)體里,之后find_e820_area()就可以從里面分配內(nèi)存了。分配方式采用簡(jiǎn)單的線性查找,并把分配出去的空間通過reserve_early()記錄到early_res這個(gè)結(jié)構(gòu)中,這些信息將會(huì)在bootmem allocator的初始化時(shí)用來置位那些已分配的物理內(nèi)存區(qū)域。舉例來說,當(dāng)系統(tǒng)要建立kernel頁(yè)表時(shí),需要申請(qǐng)頁(yè)表本身所占的內(nèi)存,于是調(diào)用one_page_table_init(),它發(fā)現(xiàn)bootmem allocator尚不可用,于是調(diào)用alloc_low_page(),這個(gè)函數(shù)就會(huì)到[table_start, start_end]這個(gè)區(qū)域里去拿內(nèi)存,而這塊內(nèi)存是在之前find_early_table_space()中通過find_e820_area()申請(qǐng)出來的。當(dāng)kernel頁(yè)表建立完后,reserve_early()被調(diào)用,它將[table_start, table_end]這塊區(qū)域以"PGTABLE"為label記錄下來。

然后是bootmem allocator,它和e820直接分配一樣,也是一個(gè)中間過渡產(chǎn)物。bootmem allocator,顧名思義就是在系統(tǒng)啟動(dòng)時(shí)候用的臨時(shí)內(nèi)存分配器。它在zone allocator建立好之后就被禁用,而在其中仍然空閑的區(qū)域會(huì)被回收到zone allocator中。bootmem allocator是一種基于bitmap的分配器,因此速度也很快。從bootmem allocator分配使用函數(shù)alloc_bootmem()。

再就是zone allocator。我們知道典型的系統(tǒng)上有三個(gè)zone:ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM。系統(tǒng)為每個(gè)zone都建立了我們熟悉的buddy system。簡(jiǎn)單地說,buddy system把物理內(nèi)存區(qū)域按2的n次方(n稱為order)掛在zone->free_area上。分配的時(shí)候拆分它們直到滿足分配申請(qǐng)要求,釋放的時(shí)候再進(jìn)行合并。從zone allocator分配和釋放分別用函數(shù)alloc_page()和free_page()。

Buddy system非常高效,但帶來了內(nèi)部碎片問題,因?yàn)樗荒芊峙涑?的0次方到2的MAX_ORDER次方的頁(yè),而且它也不利于硬件cache的利用。而內(nèi)核中經(jīng)常會(huì)頻繁申請(qǐng)固定大小的內(nèi)存如process descriptor, open file object等。如果每次都從buddy system中申請(qǐng),既費(fèi)時(shí)間又費(fèi)空間。出于空間和時(shí)間的效率考慮,于是有了slab allocator。slab allocator相當(dāng)于將內(nèi)存資源按每種固定大小進(jìn)行緩存,放在cache中。系統(tǒng)要的時(shí)候直接從這個(gè)cache里拿,而釋放時(shí)則不是真的釋放,而是放回到cache中。slab allocator維護(hù)很多cache,每個(gè)cache中包含同一類型的boject。cache又劃分為slab,slab通常包含幾個(gè)連接的物理頁(yè),其中存放在被分配的或者尚空閑的object。對(duì)于slab allocator中的內(nèi)存資源,調(diào)用kmalloc()或者直接調(diào)用kmem_cache_alloc()進(jìn)行分配,調(diào)用kfree()或者直接調(diào)用kmem_cache_free()進(jìn)行釋放。當(dāng)kmem_cache_alloc()被調(diào)用且cache中沒有object時(shí),會(huì)調(diào)用cache_grow()來增加cache中的slab,這也是slab的創(chuàng)建過程。cache_grow()繼而調(diào)用kmem_getpages()為object分配物理內(nèi)存。而kmem_getpages最終會(huì)到buddy system中去分配(kmem_getpages() => alloc_pages_node() => __alloc_pages())。因此我們說slab allocator不是buddy system的替代,還是加強(qiáng)。

之后,系統(tǒng)的內(nèi)存管理系統(tǒng)就初步建立好了。系統(tǒng)中的內(nèi)存資源有兩種-虛擬空間和物理空間。在kernel態(tài),用vmalloc()申請(qǐng)?zhí)摂M空間,同時(shí)它也調(diào)用了alloc_page()申請(qǐng)物理空間,再映射到虛擬空間中。而kmalloc可以直接從slab allocator中申請(qǐng)物理空間,而slab allocator中如果內(nèi)存不夠了再到buddy system中去分配。這樣申請(qǐng)來的物理空間在虛擬地址空間中還沒有顯式映射,當(dāng)然了,如果是low mem部分則已經(jīng)在系統(tǒng)初始化時(shí)被映射到PAGE_OFFSET處了。而user態(tài)中如果app調(diào)用malloc這樣的函數(shù),malloc會(huì)調(diào)用mmap,而mmap會(huì)申請(qǐng)調(diào)用進(jìn)程的虛擬空間,這里虛擬空間還沒有對(duì)應(yīng)的物理頁(yè)。只有真地訪問時(shí)發(fā)生page fault了,在pagefault handler里才會(huì)從buddy system中去分配物理頁(yè)。



?

Linux Kernel啟動(dòng)過程中的內(nèi)存管理


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 日本欧美一区二区三区乱码 | 色视频在线免费 | 真人一级一级特黄高清毛片 | 成人在线免费观看视频 | 欧美日韩亚洲国内综合网香蕉 | 久久久噜噜噜久久网 | 四虎精品成人免费影视 | 欧美专区在线观看 | 五月天色中色 | 久99频这里只精品23热 视频 | 奇米免费视频 | 亚洲精品欧美精品国产精品 | 亚洲欧洲日本精品 | bbw老妇bbwbbwass| 久久天天躁狠狠躁夜夜躁 | 日韩中文字幕一区 | 国产成人精品视频播放 | 青青青手机视频 | 免费看久久| 亚洲精品第一区二区在线 | 高清欧美一区二区三区 | 亚洲精品成人网 | 国产精品爱久久久久久久 | 一级毛片aaa片免费观看 | 成人亚洲在线 | 国内精品伊人久久久影视 | 色噜噜五月综合激情久久爱 | 国产乱码精品一区二区三上 | 国产网址 | 国产玖玖在线 | 欧美理论在线观看 | 一区二区三区欧美日韩 | 不卡福利视频 | 国外成人免费高清激情视频 | 一级黄网 | 久久草在线 | 日韩美女强理论片 | 色婷婷网| 91手机看片国产永久免费 | 奇米第七色 | 伊人黄网|