第2部分第5次課 linux26內(nèi)核之內(nèi)存管理_第1頁
第2部分第5次課 linux26內(nèi)核之內(nèi)存管理_第2頁
第2部分第5次課 linux26內(nèi)核之內(nèi)存管理_第3頁
第2部分第5次課 linux26內(nèi)核之內(nèi)存管理_第4頁
第2部分第5次課 linux26內(nèi)核之內(nèi)存管理_第5頁
已閱讀5頁,還剩164頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、嵌入式Linux內(nèi)核體系(tx)架構(gòu)李超lichao一百六十九頁內(nèi)存(ni cn)管理Linux的內(nèi)存(ni cn)管理 進(jìn)程的用戶空間管理請(qǐng)頁機(jī)制物理內(nèi)存的管理、分配與回收交換機(jī)制內(nèi)存管理示例共一百六十九頁P(yáng)ART 4.1 linux內(nèi)存(ni cn)管理共一百六十九頁內(nèi)存(ni cn)管理內(nèi)存管理是一個(gè)操作系統(tǒng)必不可少,并且非常重要的一環(huán)。Linux的成功和它優(yōu)秀的內(nèi)存管理聯(lián)系非常密切,因?yàn)橐粋€(gè)系統(tǒng)的高效性欲穩(wěn)定性往往決定于它的內(nèi)存管理機(jī)制。對(duì)每個(gè)程序員來說.他們都希望有無窮大的快速的內(nèi)存,然而,現(xiàn)階段是不可能的。為了解決無窮大,Linux 引入了虛擬存儲(chǔ)系統(tǒng);為

2、了解決快速,Linux 引入了cache、交換(jiohun)機(jī)制等等,以使的存儲(chǔ)系統(tǒng),在容量上接近硬盤,在速度上接近c(diǎn)ache。共一百六十九頁內(nèi)存(ni cn)的層次結(jié)構(gòu) 每個(gè)程序員都喜歡無窮大、快速的存儲(chǔ)器,同時(shí)又希望它是廉價(jià)的。但不幸的是,當(dāng)前技術(shù)沒有能夠提供這樣的存儲(chǔ)器,大部分的計(jì)算機(jī)都有一個(gè)存儲(chǔ)器層次結(jié)構(gòu):即少量(sholing)的非??焖佟嘿F、易變的高速緩存(cache);若干兆字節(jié)的中等速度、中等價(jià)格、易變的主存儲(chǔ)器(RAM);數(shù)百兆或數(shù)千兆的低速、廉價(jià)、不易變的磁盤。 這些資源的合理使用與否直接關(guān)系著系統(tǒng)的效率。 共一百六十九頁內(nèi)存(ni cn)管理地址映射機(jī)制,就是在虛擬內(nèi)

3、存與物理內(nèi)存上的一個(gè)橋梁。要做的事情可能(knng)就是通過幾個(gè)不同的表,把虛擬地址轉(zhuǎn)換成物理地址,把物理地址轉(zhuǎn)化虛擬地址。共一百六十九頁虛擬內(nèi)存的基本(jbn)思想:在計(jì)算機(jī)中運(yùn)行的程序,其代碼、數(shù)據(jù)和堆棧的總量可以超過實(shí)際內(nèi)存的大小,操作系統(tǒng)只將當(dāng)前使用的程序塊保留在內(nèi)存中,其余的程序塊則保留在磁盤上。必要時(shí),操作系統(tǒng)負(fù)責(zé)在磁盤和內(nèi)存之間交換程序塊。擴(kuò)大(kud)了的記憶虛擬內(nèi)存共一百六十九頁虛擬內(nèi)存、內(nèi)核空間(kngjin)和用戶空間(kngjin)內(nèi)核(ni h)空間(1GB)進(jìn)程1的用戶空間(3GB)進(jìn)程2的用戶空間(3GB)進(jìn)程n的用戶空間(3GB)虛擬地址空間0 x0000000

4、00 xBFFFFFFF0 xC00000000 xFFFFFFFF每個(gè)進(jìn)程通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核,Linux內(nèi)核空間由系統(tǒng)內(nèi)的所有進(jìn)程共享。從進(jìn)程的角度來看,每個(gè)進(jìn)程擁有4GB的虛擬地址空間(也叫虛擬內(nèi)存)。每個(gè)進(jìn)程有各自的私有用戶空間(0-3G),這個(gè)空間對(duì)系統(tǒng)中的其他進(jìn)程是不可見的。最高的1GB內(nèi)核空間則為所有進(jìn)程以及內(nèi)核所共享。 共一百六十九頁虛擬內(nèi)存共4G字節(jié)(z ji),分為兩部分:內(nèi)核空間(最高的1G字節(jié))用戶空間(較低的3G字節(jié))每個(gè)進(jìn)程最大擁有3G字節(jié)私有虛存空間地址轉(zhuǎn)換通過頁表把虛存空間的一個(gè)地址轉(zhuǎn)換為物理空間中的實(shí)際地址。虛擬內(nèi)存、內(nèi)核(ni h)空間和用戶空間共一百六十九

5、頁任意一個(gè)時(shí)刻,在一個(gè)CPU上只有一個(gè)進(jìn)程在運(yùn)行。所有對(duì)于此CPU來講,在這個(gè)時(shí)刻,整個(gè)系統(tǒng)(xtng)只存在一個(gè)4GB的虛擬地址空間。盡管每個(gè)進(jìn)程都可以有4GB的虛擬地址空間,但是在CPU眼里,只有一個(gè)虛擬地址空間存在當(dāng)進(jìn)程發(fā)生切換,頁表也將更換為相應(yīng)進(jìn)程的頁表,這就可以使每個(gè)進(jìn)程都有自己的虛擬地址空間而互不影響。所以,在任意時(shí)刻,對(duì)于一個(gè)CPU來說,只需有當(dāng)前進(jìn)程的頁表,就可以實(shí)現(xiàn)虛擬地址到物理地址的轉(zhuǎn)換虛擬內(nèi)存、內(nèi)核空間(kngjin)和用戶空間(kngjin)共一百六十九頁內(nèi)核空間由所有進(jìn)程共享,其中存放的是內(nèi)核代碼和數(shù)據(jù),即“內(nèi)核映象”(kernel image)進(jìn)程的用戶空間中存放

6、的是用戶程序的代碼和數(shù)據(jù)內(nèi)核空間映射到物理(wl)內(nèi)存總是從最低地址(0 x00000000)開始,使之在內(nèi)核空間與物理內(nèi)存之間建立簡(jiǎn)單的線性映射關(guān)系。內(nèi)核空間到物理(wl)內(nèi)存的映射共一百六十九頁03G4G0X虛擬地址空間(kngjin) 物理(wl)內(nèi)存圖4.1 內(nèi)核的虛擬地址空間到物理地址空間的映射 內(nèi)核空間到物理內(nèi)存的映射物理地址與虛擬地址之間的位移量就是3GB(0 xC0000000) ,在Linux代碼中就叫做PAGE_OFFSET。對(duì)于內(nèi)核空間而言,給定一個(gè)虛地址x,其物理地址為“x- PAGE_OFFSET”。這種映射關(guān)系只適應(yīng)于內(nèi)核空間,而用戶空間的地址映射要復(fù)雜得多,它是通

7、過分頁機(jī)制完成的。共一百六十九頁Linux虛擬內(nèi)存的實(shí)現(xiàn)需要多種機(jī)制(jzh)的支持地址映射機(jī)制請(qǐng)頁機(jī)制內(nèi)存分配和回收機(jī)制交換機(jī)制緩存和刷新機(jī)制虛擬內(nèi)存實(shí)現(xiàn)(shxin)機(jī)制共一百六十九頁地址映射圖4.2 虛擬內(nèi)存實(shí)現(xiàn)(shxin)機(jī)制及之間的關(guān)系虛擬內(nèi)存實(shí)現(xiàn)機(jī)制(jzh)及之間的關(guān)系共一百六十九頁虛擬內(nèi)存實(shí)現(xiàn)(shxin)機(jī)制及之間的關(guān)系首先內(nèi)核通過映射機(jī)制把進(jìn)程的虛擬地址映射到物理地址,在進(jìn)程運(yùn)行時(shí),如果內(nèi)核發(fā)現(xiàn)進(jìn)程要訪問的頁沒有在物理內(nèi)存時(shí),就發(fā)出了請(qǐng)頁要求;如果有空閑的內(nèi)存可供分配,就請(qǐng)求分配內(nèi)存(于是用到了內(nèi)存的分配和回收),并把正在使用的物理頁記錄在頁緩存中(使用了緩存機(jī)制);如果

8、沒有足夠的內(nèi)存可供分配,那么就調(diào)用交換機(jī)制,騰出(tn ch)一部分內(nèi)存;另外在地址映射中要通過TLB(轉(zhuǎn)換查找緩沖區(qū), Translation Lookaside Buffer) 來尋找物理頁;交換機(jī)制中也要用到交換緩存,并且把物理頁內(nèi)容交換到交換文件中后也要修改頁表來映射文件地址共一百六十九頁內(nèi)存(ni cn)尋址分頁機(jī)制為了減少地址轉(zhuǎn)換所要求的總線周期數(shù)量,最近存取的頁目錄和頁表會(huì)被存放在處理器的緩沖器件中,該緩沖器件被稱為轉(zhuǎn)換查找緩沖區(qū)TLB ( Transla-tion Lookaside Buffer)。TLB可以(ky)滿是大多數(shù)讀頁目錄和頁表的請(qǐng)求而無需使用總線周期。只有當(dāng)TL

9、B中不包含要求的頁表項(xiàng)時(shí)才會(huì)使用額外的總線周期從內(nèi)存中讀取頁表項(xiàng),這通常在一個(gè)頁表項(xiàng)很長(zhǎng)時(shí)間沒有存取過時(shí)才會(huì)出現(xiàn)這種情況共一百六十九頁P(yáng)ART 4.2 用戶(yngh)進(jìn)程管理共一百六十九頁每個(gè)進(jìn)程(jnchng)經(jīng)編譯、鏈接后形成的二進(jìn)制映像文件有一個(gè)代碼段和數(shù)據(jù)段,其中代碼段在下,數(shù)據(jù)段在上。數(shù)據(jù)段中包含了所有靜態(tài)分配的數(shù)據(jù)空間,即全局變量和所有聲明為static的局部變量,這些空間是進(jìn)程所必需的,是在建立一個(gè)進(jìn)程的運(yùn)行映像時(shí)就分配好的。進(jìn)程的用戶空間(kngjin)管理共一百六十九頁由圖可以看出,堆棧段安排在用戶空間的頂部,運(yùn)行時(shí)由頂向下延伸;代碼段和數(shù)據(jù)段則在低部,運(yùn)行時(shí)并不向上(xi

10、ngshng)延伸。從數(shù)據(jù)段的頂部到堆棧段地址的下沿這個(gè)區(qū)間是一個(gè)巨大的空洞,這就是進(jìn)程在運(yùn)行時(shí)調(diào)用malloc()可以動(dòng)態(tài)分配的空間,也叫動(dòng)態(tài)內(nèi)存或堆。進(jìn)程的用戶(yngh)空間管理堆棧段空洞數(shù)據(jù)段代碼段進(jìn)程的用戶空間(3G) 共一百六十九頁每個(gè)進(jìn)程擁有3GB的用戶空間,但其地址都是虛地址,因此用戶進(jìn)程在這個(gè)虛擬內(nèi)存中并不能真正地運(yùn)行起來,必須把用戶空間中的虛地址最終映射到物理存儲(chǔ)空間才行,而這種映射的建立和管理是由內(nèi)核完成的。所謂向內(nèi)核申請(qǐng)一塊空間,實(shí)際上是請(qǐng)求內(nèi)核分配一塊虛存區(qū)間(q jin)和相應(yīng)的若干物理頁面,并建立映射關(guān)系進(jìn)程的用戶空間(kngjin)管理共一百六十九頁內(nèi)核在創(chuàng)建進(jìn)

11、時(shí)并不是為整個(gè)用戶空間都分配好相應(yīng)的物理空間,而是根據(jù)需要才正分配一些物理頁面并建立映射。系統(tǒng)利用了請(qǐng)頁機(jī)制避免對(duì)物理內(nèi)存的過分使用。因?yàn)檫M(jìn)程訪問的用戶空間中的頁可能當(dāng)前(dngqin)不在物理內(nèi)存中,這時(shí),操作系統(tǒng)通過請(qǐng)頁機(jī)制把數(shù)據(jù)從磁盤裝入到物理內(nèi)存。為此,系統(tǒng)需要修改進(jìn)程的頁表,以標(biāo)志用戶空間中的頁已經(jīng)裝入到物理頁面中。進(jìn)程的用戶空間(kngjin)管理共一百六十九頁Linux把進(jìn)程的用戶空間劃分為一個(gè)個(gè)區(qū)間,便于管理一個(gè)進(jìn)程的用戶地址(dzh)空間主要由mm_struct結(jié)構(gòu)和vm_area_structs結(jié)構(gòu)來描述。mm_struct結(jié)構(gòu)對(duì)進(jìn)程整個(gè)用戶空間進(jìn)行描述vm_area_st

12、ructs結(jié)構(gòu)對(duì)用戶空間中各個(gè)區(qū)間(簡(jiǎn)稱虛存區(qū))進(jìn)行描述 進(jìn)程用戶(yngh)空間 共一百六十九頁struct mm_struct atomic_t count; pgd_t * pgd; int map_count; struct semaphore mmap_sem; unsigned long start_code,end_code,start_data,end_data; unsigned long start_brk, brk, start_stack; unsigned long arg_start, arg_end, env_start, env_end; unsigned lo

13、ng rss, total_vm, locked_vm; unsigned long def_flags; struct vm_area_struct *mmap, *mmap_avl, *mmap_cache; unsigned long swap_cnt; unsigned long swap_address; ; mm_struct 結(jié)構(gòu)(jigu) 共一百六十九頁域名說 明count對(duì)mm_struct結(jié)構(gòu)的引用進(jìn)行計(jì)數(shù)。為了在Linux中實(shí)現(xiàn)線程,內(nèi)核調(diào)用clone派生一個(gè)線程,線程和調(diào)用進(jìn)程共享用戶空間(kngjin),即mm_struct結(jié)構(gòu),派生后系統(tǒng)會(huì)累加mm_struct中

14、的引用計(jì)數(shù)。pgd進(jìn)程的頁目錄(ml)基地址,當(dāng)調(diào)度程序調(diào)度一個(gè)進(jìn)程運(yùn)行時(shí),就將這個(gè)地址轉(zhuǎn)成物理地址,并寫入控制寄存器(CR3)map_count在進(jìn)程的整個(gè)用戶空間中虛存區(qū)的個(gè)數(shù)semaphore對(duì)mm_struct結(jié)構(gòu)進(jìn)行串行訪問所使用的信號(hào)量Start_code,end_code, start_data, end_data進(jìn)程的代碼段和數(shù)據(jù)段的起始地址和終止地址start_brk, brk, start_stack;每個(gè)進(jìn)程都有一個(gè)特殊的地址區(qū)間,這個(gè)區(qū)間就是所謂的堆,也就是圖4.4中的空洞。前兩個(gè)域分別描述堆的起始地址和終止的地址,最后一個(gè)域描述堆棧段的起始地址。arg_start,

15、arg_end, env_start, env_end命令行參數(shù)所在的堆棧部分的起始地址和終止地址;環(huán)境串所在的堆棧部分的起始地址和終止地址rss, total_vm, locked_vm進(jìn)程貯留在物理內(nèi)存中的頁面數(shù),進(jìn)程所需的總頁數(shù),被鎖定在物理內(nèi)存中的頁數(shù)。mmapvm_area_struct虛存區(qū)結(jié)構(gòu)形成一個(gè)單鏈表,其基址由小到大排列mmap_avlvm_area_struct虛存區(qū)結(jié)構(gòu)形成一個(gè)顆AVL平衡樹mmap_cache最近一次用到的虛存區(qū)很可能下一次還要用到,因此,把最近用到的虛存區(qū)結(jié)構(gòu)放入高速緩存,這個(gè)虛存區(qū)就由mmap_cache指向。共一百六十九頁為什么把進(jìn)程的用戶空間分

16、成一個(gè)個(gè)空間,這是因?yàn)槊總€(gè)虛存區(qū)的來源可能不同,有的來自可執(zhí)行映像,有的來自共享庫,而有的則可能是動(dòng)態(tài)分配的內(nèi)存區(qū)。不同的區(qū)間可能具有不同的訪問權(quán)限(qunxin),不同的操作。因此Linux把進(jìn)程的用戶空間分割,并利用了虛存區(qū)處理函數(shù)(vm_ops)來抽象對(duì)不同來源的虛存區(qū)的處理方法。虛存區(qū)共一百六十九頁struct vm_area_struct struct mm_struct * vm_mm; unsigned long vm_start; unsigned long vm_end; pgprot_t vm_page_prot; unsigned short vm_flags; stru

17、ct vm_area_struct *vm_next; short vm_avl_height; struct vm_area_struct *vm_avl_left, *vm_avl_right; struct vm_operations_struct * vm_ops; struct vm_area_struct *vm_next_share, *vm_pprev_share; unsigned long vm_offset; struct file * vm_file; unsigned long vm_pte; ; VM_AREA_STRUCT 結(jié)構(gòu)(jigu) 共一百六十九頁域名說

18、明vm_mm指向虛存區(qū)所在的mm_struct結(jié)構(gòu)的指針。vm_start,vm_end虛存區(qū)的起始地址和終止地址。vm_page_prot虛存區(qū)的保護(hù)權(quán)限。vm_flags虛存區(qū)的標(biāo)志。vm_next構(gòu)成線性鏈表的指針,按虛存區(qū)基址從小到大排列。vm_avl_height,vm_avl_left,vm_avl_right這3個(gè)域在一起構(gòu)成AVL樹,其中vm_avl_height是該節(jié)點(diǎn)距根節(jié)點(diǎn)的高度,vm_avl_left和vm_avl_right分別是該節(jié)點(diǎn)的左右兩個(gè)子樹。vm_ops對(duì)虛存區(qū)進(jìn)行操作的函數(shù)。這些給出了可以對(duì)虛存區(qū)中的頁所進(jìn)行的操作。共一百六十九頁根據(jù)虛擬內(nèi)存抽象模型(mx

19、ng),每個(gè)進(jìn)程都可以互不干擾的使用所有虛擬地址。進(jìn)程的虛擬內(nèi)存空間被劃分為小的虛擬內(nèi)存區(qū)域來使用。每個(gè)內(nèi)存區(qū)域是一段具有相同屬性的虛擬地址空間。Linux用vm_area_struct(include/linux/mm.h)來描述一個(gè)虛擬內(nèi)存區(qū)域。一個(gè)進(jìn)程的所有內(nèi)存區(qū)域組織成一個(gè)雙向鏈表。進(jìn)程用了一個(gè)指向vm_area_struct鏈表的指針,來描述進(jìn)程虛擬內(nèi)存空間的一個(gè)區(qū)域,包括對(duì)該區(qū)域的起始和終止地址的描述。進(jìn)程可以通過vm_operation_struct(include/linux/mm.h)對(duì)這些區(qū)域進(jìn)行操作。虛存區(qū)共一百六十九頁Linux在這里利用了面向?qū)ο蟮乃枷?,即把一個(gè)虛存區(qū)

20、看成一個(gè)對(duì)象,用vm_area_structs描述了這個(gè)對(duì)象的屬性,其中的vm_operation結(jié)構(gòu)描述了在這個(gè)對(duì)象上的操作,其定義如下:struct vm_operations_struct void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area);struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int unused) vm_operations結(jié)構(gòu)中包含的是函數(shù)指針;

21、其中,open、close分別用于虛存區(qū)的打開、關(guān)閉,而nopage是當(dāng)虛存頁面不在物理內(nèi)存而引起的“缺頁異常”時(shí)所應(yīng)該(ynggi)調(diào)用的函數(shù)。 虛存區(qū)共一百六十九頁當(dāng)加載關(guān)于進(jìn)程虛擬地址空間的頁面時(shí),一系列的vm_area_struct將自動(dòng)生成,每一個(gè)vm_area_struct描述進(jìn)程的一部分,如執(zhí)行代碼、數(shù)據(jù)等。Linux支持了多數(shù)標(biāo)準(zhǔn)的虛擬內(nèi)存操作,如讀取、關(guān)閉、共享、缺頁等。一旦(ydn)vm_area_struct結(jié)構(gòu)生成,就可以通過該結(jié)構(gòu)中的指向vm_operation_struct的指針進(jìn)行虛擬內(nèi)存操作了虛存區(qū)共一百六十九頁Linux對(duì)于虛存區(qū)的操作定義在vm_operat

22、ion_ struct數(shù)據(jù)結(jié)構(gòu)(sh j ji u)中,通過在vm_area_struct結(jié)構(gòu)中使用指針vm_ops來確定該虛存區(qū)可以進(jìn)行的一系列操作struct vm_operations_struct /* 打開操作,當(dāng)內(nèi)核生成一個(gè)虛存區(qū)后或者當(dāng)虛存區(qū)被復(fù)制后,就用該命令打開。*/void (*open)(struct vm_area_struct * area);/* 關(guān)閉操作,當(dāng)內(nèi)核銷毀一個(gè)虛存區(qū)時(shí),就調(diào)用該命令。*/void (*close)(struct vm_area_struct * area); 虛存區(qū)共一百六十九頁/* 處理缺頁異常,當(dāng)進(jìn)程訪問一個(gè)不屬于內(nèi)存的有效頁面時(shí),就

23、會(huì)調(diào)用該命令(mng lng),返回該頁的物理地址。*/ void (*nopage)(int error_code, struct vm_area_struct * area, unsigned long address);虛存區(qū)共一百六十九頁進(jìn)程控制塊是內(nèi)核中的核心數(shù)據(jù)結(jié)構(gòu)。在進(jìn)程的 task_struct 結(jié)構(gòu)中包含一個(gè)mm域,它是指向 mm_struct 結(jié)構(gòu)的指針。而進(jìn)程的 mm_struct結(jié)構(gòu)則包含進(jìn)程的可執(zhí)行(zhxng)映像信息以及進(jìn)程的頁目錄指針pgd等。該結(jié)構(gòu)還包含有指向 vm_area_struct 結(jié)構(gòu)的幾個(gè)指針,每個(gè) vm_area_struct 代表進(jìn)程的一個(gè)虛擬

24、地址區(qū)間。 相關(guān)數(shù)據(jù)結(jié)構(gòu)(sh j ji u)間的關(guān)系共一百六十九頁相關(guān)數(shù)據(jù)結(jié)構(gòu)(sh j ji u)之間的關(guān)系示意圖 共一百六十九頁系統(tǒng)以用戶虛擬內(nèi)存地址的降序排列 vm_area_struct。在進(jìn)程的運(yùn)行(ynxng)過程中,Linux 要經(jīng)常為進(jìn)程分配虛存區(qū),因此,vm_area_struct 結(jié)構(gòu)的訪問時(shí)間就成了性能的關(guān)鍵因素。為此,除鏈表結(jié)構(gòu)外,Linux 還利用AVL平衡樹樹來組織 vm_area_struct。通過這種樹結(jié)構(gòu),Linux 可以快速定位某個(gè)虛存區(qū)。虛存區(qū)共一百六十九頁每個(gè)進(jìn)程都有自己的用戶空間,但是調(diào)用clone()函數(shù)創(chuàng)建的內(nèi)核線程時(shí)共享父進(jìn)程的用戶空間。寫時(shí)復(fù)

25、制方法,子進(jìn)程繼承父進(jìn)程的用戶空間:只要頁是只讀的,就依然共享它們。當(dāng)其中的一個(gè)進(jìn)程試圖寫入某一個(gè)頁時(shí),這個(gè)頁就被復(fù)制一份;一段時(shí)間之后,所創(chuàng)建的進(jìn)程通常獲得與父進(jìn)程不一樣的完全屬于自己的用戶空間。而對(duì)于(duy)內(nèi)核線程來說,它使用父進(jìn)程的用戶空間。因此創(chuàng)建內(nèi)核線程比創(chuàng)建普通進(jìn)程相應(yīng)要快得多,而且只要父進(jìn)程和子進(jìn)程謹(jǐn)慎地調(diào)整它們的訪問順序,就可以認(rèn)為頁的共享是有益的。由此,進(jìn)程用戶空間的創(chuàng)建主要依賴于父進(jìn)程,而且,在創(chuàng)建的過程中所做的工作僅僅是mm_struc結(jié)構(gòu)的建立,vm_area_struct結(jié)構(gòu)的建立以及頁目錄和頁表的建立,并沒有真正地復(fù)制一個(gè)物理頁面,這也是為什么Linux內(nèi)核能迅

26、速地創(chuàng)建進(jìn)程的原因之一。創(chuàng)建(chungjin)進(jìn)程用戶空間共一百六十九頁fork()系統(tǒng)調(diào)用在創(chuàng)建新進(jìn)程時(shí)也為該進(jìn)程創(chuàng)建完整的用戶空間具體而言,是通過拷貝或共享父進(jìn)程的用戶空間來實(shí)現(xiàn)的,即內(nèi)核調(diào)用copy_mm( )函數(shù),為新進(jìn)程建立所有(suyu)頁表和mm_struct結(jié)構(gòu)創(chuàng)建進(jìn)程(jnchng)用戶空間共一百六十九頁當(dāng)通過exec()系統(tǒng)調(diào)用開始執(zhí)行一個(gè)進(jìn)程時(shí),進(jìn)程的可執(zhí)行映像(包括代碼段、數(shù)據(jù)段等)必須(bx)裝入到進(jìn)程的用戶空間。如果該進(jìn)程用到了任何一個(gè)共享庫,則共享庫也必須(bx)裝入到進(jìn)程的用戶空間由此,Linux并不將映像裝入到物理內(nèi)存,相反,可執(zhí)行文件只是被連接到進(jìn)程的用戶

27、空間中。隨著進(jìn)程的運(yùn)行,被引用的程序部分會(huì)由操作系統(tǒng)裝入到物理內(nèi)存,這種將映像鏈接到進(jìn)程用戶空間的方法被稱為“虛存映射” 。虛存映射:即把文件從磁盤映射到進(jìn)程的用戶空間,對(duì)文件的訪問轉(zhuǎn)化為對(duì)虛存區(qū)的訪問虛存映射(yngsh)共一百六十九頁有兩種類型的虛存映射:共享的:有幾個(gè)進(jìn)程共享這一映射,也就是說,如果一個(gè)進(jìn)程對(duì)共享的虛存區(qū)進(jìn)行寫,其它進(jìn)程都能感覺到,而且會(huì)修改磁盤上對(duì)應(yīng)的文件。私有的:進(jìn)程創(chuàng)建的這種映射只是為了讀文件,而不是寫文件,因此,對(duì)虛存區(qū)的寫操作(cozu)不會(huì)修改磁盤上的文件,由此可以看出,私有映射的效率要比共享映射的高。除了這兩種映射外,如果映射與文件無關(guān),就叫匿名映射。虛存映

28、射(yngsh)共一百六十九頁當(dāng)可執(zhí)行映像映射到進(jìn)程的用戶空間時(shí),將產(chǎn)生一組 vm_area_struct 結(jié)構(gòu)來描述各個(gè)虛擬區(qū)間的起始點(diǎn)和終止點(diǎn)每個(gè) vm_area_struct 結(jié)構(gòu)代表可執(zhí)行映像的一部分,可能是可執(zhí)行代碼,可能是初始化的變量或未初始化的數(shù)據(jù),也可能是剛打開的一個(gè)文件,這些映射都是在函數(shù)do_mmap()中來實(shí)現(xiàn)的隨著 vm_area_struct 結(jié)構(gòu)的生成,這些結(jié)構(gòu)所描述的虛擬內(nèi)存區(qū)間上的標(biāo)準(zhǔn)操作函數(shù)也由 Linux 初始化。但要明確,在這一步(y b)還沒有建立從虛擬內(nèi)存到物理內(nèi)存的映射虛存映射(yngsh)共一百六十九頁例:exam.cint main()print

29、f(“virtual area test!”);進(jìn)程(jnchng)的虛存區(qū)舉例地址范圍許可權(quán)偏移量 所映射的文件08048000-08049000 r-xp00000000/home/test/exam08049000-0804a000rw-p 00001000/home/test/exam 40000000-40015000r-xp00000000/lib/ld-2.3.2.so40015000-40016000rw-p00015000/lib/ld-2.3.2.so40016000-40017000rw-p00000000匿名4002-xp 00000000/

30、lib/libc-2.3.2.so40159000-4015e000rw-p0012f000/lib/libc-2.3.2.so4015w-p00000000匿名bfffe000-c0000000 rwxpfffff000匿名 exam進(jìn)程(jnchng)的虛存區(qū) 共一百六十九頁地址范圍許可權(quán)偏移量 所映射的文件08048000-08049000 r-xp00000000/home/test/exam08049000-0804a000rw-p 00001000/home/test/exam 40000000-40015000r-xp00000000/lib/ld-2

31、.3.2.so40015000-40016000rw-p00015000/lib/ld-2.3.2.so40016000-40017000rw-p00000000匿名4002-xp 00000000/lib/libc-2.3.2.so40159000-4015e000rw-p0012f000/lib/libc-2.3.2.so4015w-p00000000匿名bfffe000-c0000000 rwxpfffff000匿名從0 x8048000開始的虛存區(qū)是/home/test/exam文件的某一部分的虛存映射,范圍從0到0 x1000字

32、節(jié)。許可權(quán)指定這個(gè)區(qū)域(qy)是可執(zhí)行的(包含目標(biāo)代碼)、只讀的(不可寫,因?yàn)橹噶顖?zhí)行期間不能改變),并且是私有的,因此我們可以猜出這個(gè)區(qū)域(qy)映射了程序的代碼段。共一百六十九頁地址范圍許可權(quán)偏移量 所映射的文件08048000-08049000 r-xp00000000/home/test/exam08049000-0804a000rw-p 00001000/home/test/exam 40000000-40015000r-xp00000000/lib/ld-2.3.2.so40015000-40016000rw-p00015000/lib/ld-2.3.2.so40016000-40

33、017000rw-p00000000匿名4002-xp 00000000/lib/libc-2.3.2.so40159000-4015e000rw-p0012f000/lib/libc-2.3.2.so4015w-p00000000匿名bfffe000-c0000000 rwxpfffff000匿名從0 x8049000開始(kish)的虛存區(qū)是/home/test/exam文件的另一部分虛存映射,因?yàn)樵S可權(quán)指定這個(gè)私有區(qū)域可以被寫,我們可以推斷出它映射了程序的數(shù)據(jù)段。共一百六十九頁地址范圍許可權(quán)偏移量 所映射的文件08048000-08

34、049000 r-xp00000000/home/test/exam08049000-0804a000rw-p 00001000/home/test/exam 40000000-40015000r-xp00000000/lib/ld-2.3.2.so40015000-40016000rw-p00015000/lib/ld-2.3.2.so40016000-40017000rw-p00000000匿名4002-xp 00000000/lib/libc-2.3.2.so40159000-4015e000rw-p0012f000/lib/libc-2.3.2.so4015

35、w-p00000000匿名bfffe000-c0000000 rwxpfffff000匿名類似地,從0 x40000000、0 x40015000開始的虛存區(qū)分別(fnbi)對(duì)應(yīng)動(dòng)態(tài)鏈接庫/lib/ld-2.3.2.so的 代碼段和數(shù)據(jù)段。從40016000開始的虛存區(qū)是匿名的,也就是說,它與任何文件都無關(guān),可以推斷出它映射了連接程序的bbs段(未初始化的數(shù)據(jù)段)。共一百六十九頁地址范圍許可權(quán)偏移量 所映射的文件08048000-08049000 r-xp00000000/home/test/exam08049000-0804a000rw-p 00001000/ho

36、me/test/exam 40000000-40015000r-xp00000000/lib/ld-2.3.2.so40015000-40016000rw-p00015000/lib/ld-2.3.2.so40016000-40017000rw-p00000000匿名4002-xp 00000000/lib/libc-2.3.2.so40159000-4015e000rw-p0012f000/lib/libc-2.3.2.so4015w-p00000000匿名bfffe000-c0000000 rwxpfffff000匿名緊接著的三個(gè)區(qū)映

37、射了C庫程序/lib/libc-2.3.2.so的代碼段、數(shù)據(jù)段和bss段。最后(zuhu)一個(gè)虛擬區(qū)是進(jìn)程的堆棧。 共一百六十九頁與用戶空間相關(guān)的主要(zhyo)系統(tǒng)調(diào)用 系統(tǒng)調(diào)用描述fork()創(chuàng)建具有新的用戶空間的進(jìn)程,用戶空間中的所有頁被標(biāo)記為“寫時(shí)復(fù)制”,且由父子進(jìn)程共享,當(dāng)其中的一個(gè)進(jìn)程所訪問的頁不在內(nèi)存時(shí),這個(gè)頁就被復(fù)制一份。mmap()在進(jìn)程的用戶空間內(nèi)創(chuàng)建一個(gè)新的虛存區(qū)。munmap()銷毀一個(gè)完整的虛存區(qū)或其中的一部分,如果要取消的虛存區(qū)位于某個(gè)虛存區(qū)的中間,則這個(gè)虛存區(qū)被劃分為兩個(gè)虛存區(qū)。exec()裝入新的可執(zhí)行文件以代替當(dāng)前用戶空間。exit()銷毀進(jìn)程的用戶空間及其

38、所有的虛存區(qū)。共一百六十九頁與用戶空間相關(guān)的主要(zhyo)系統(tǒng)調(diào)用 對(duì)fork()、exec()、exit()這幾個(gè)系統(tǒng)調(diào)用(dioyng)已有所了解,下面說明在用戶程序中如何調(diào)用(dioyng)mmap(),其原型為:void *mmap (void *start , int length, int prot, int flags, int fd, int offset) start為映射到用戶空間的起始地址 length則為長(zhǎng)度(以字節(jié)為單位) 參數(shù)prot表示對(duì)所映射區(qū)間的訪問模式,如可寫、可讀、可執(zhí)行等 參數(shù)fd代表一個(gè)已打開的文件 offset為文件的起點(diǎn)共一百六十九頁與用戶空間相

39、關(guān)的主要(zhyo)系統(tǒng)調(diào)用 對(duì)fork()、exec()、exit()這幾個(gè)系統(tǒng)調(diào)用已有所了解,下面說明在用戶程序中如何調(diào)用mmap(),其原型為:void *mmap (void *start , int length, int prot, int flags, int fd, int offset)而flags用于其他控制目的:MAP_SHARED:與子進(jìn)程共享虛存區(qū),則對(duì)映射(yngsh)的內(nèi)存所做的修改同樣影響到文件。MAP_PRIVATE: 子進(jìn)程對(duì)這個(gè)虛存區(qū)是“寫時(shí)拷貝”,對(duì)映射的內(nèi)存所做的修改僅對(duì)該進(jìn)程可見,對(duì)文件沒有影響。MAP_LOCKED:鎖定這個(gè)虛存區(qū),不能交換。MAP

40、_ANONYMOUS:匿名區(qū),與文件無關(guān)共一百六十九頁與用戶(yngh)空間相關(guān)的主要系統(tǒng)調(diào)用 mmap系統(tǒng)調(diào)用并不是完全為了(wi le)用于共享內(nèi)存而設(shè)計(jì)的。它本身提供了不同于一般對(duì)普通文件的訪問方式,進(jìn)程可以像讀寫內(nèi)存一樣對(duì)普通文件的操作。另外,mmap()實(shí)現(xiàn)共享內(nèi)存也是其主要應(yīng)用之一。 mmap系統(tǒng)調(diào)用使得進(jìn)程之間通過映射同一個(gè)普通文件實(shí)現(xiàn)共享內(nèi)存。普通文件被映射到進(jìn)程地址空間后,進(jìn)程可以像訪問普通內(nèi)存一樣對(duì)文件進(jìn)行訪問,不必再調(diào)用read(),write()等操作。通常使用了mmap,為了“像訪問普通內(nèi)存一樣對(duì)文件進(jìn)行訪問”。實(shí)踐證明,當(dāng)要對(duì)一個(gè)文件頻繁的進(jìn)行訪問,并且指針來回移動(dòng)

41、時(shí),調(diào)用mmap比用常規(guī)的方法快很多。共一百六十九頁與用戶空間相關(guān)的主要(zhyo)系統(tǒng)調(diào)用 共一百六十九頁與用戶空間相關(guān)的主要系統(tǒng)(xtng)調(diào)用 例子,下面的程序段映射一個(gè)4字節(jié)大小(dxio)的匿名區(qū),父進(jìn)程和子進(jìn)程共享這個(gè)匿名區(qū)。#define N 10int i, sum, fd;int *result_ptr = mmap(0, 4, PROT_READ|PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0 , 0);int pid = fork();if (pid =0)for(sum=0, i=1; i=N; i+) sum+=i;*result_

42、ptr=sum;elsewait(0);printf(“result=%dn”, *result_ptr);共一百六十九頁與用戶空間相關(guān)(xinggun)的主要系統(tǒng)調(diào)用 例子(l zi),下面的程序段映射一個(gè)名為test_data的文件,文件的內(nèi)容為“Hello,World!”int i, fd;char* buf;fd = open(“test_data”, O_RDONLY);buf = mmap(0, 12, PROT_READ, MAP_PRIVATE, fd, 0);for(i=0; i0:頁已經(jīng)分配給一個(gè)或多個(gè)進(jìn)程或用戶某些內(nèi)核數(shù)據(jù)結(jié)構(gòu)flags:頁框狀態(tài),最多可以有32個(gè),每個(gè)使

43、用一個(gè)位表示共一百六十九頁頁框狀態(tài)(zhungti)在磁盤(c pn)I/O操作中涉及的頁在傳輸頁時(shí)發(fā)生I/O錯(cuò)誤為一次I/O操作剛剛訪問過的頁在完成讀操作后置位,除非發(fā)生磁盤I/O錯(cuò)誤頁已經(jīng)被修改頁在活動(dòng)或非活動(dòng)的鏈表中頁在活動(dòng)頁鏈表中包含在slab中的頁框頁框?qū)儆赯ONE_HIGHMEM管理區(qū)由ext2文件系統(tǒng)使用的標(biāo)志在x86體系結(jié)構(gòu)上沒有使用頁框留給內(nèi)核代碼使用或沒有使用共一百六十九頁隨著用戶程序的執(zhí)行和結(jié)束,系統(tǒng)需要不斷為其分配和釋放物理頁面。內(nèi)核應(yīng)該為分配一組連續(xù)的頁面而建立一種穩(wěn)定、高效的分配策略。但是,頻繁地請(qǐng)求和釋放不同大小的一組連續(xù)頁面,必然導(dǎo)致在已分配的內(nèi)存(ni cn)

44、塊中分撒著許多小塊的空閑頁面,即外碎片。由此帶來的問題是,即使這些小塊的空閑頁面加起來足以滿足所請(qǐng)求的頁面,但是要分配一個(gè)大塊的連續(xù)頁面可能根本無法滿足。為此,Linux使用著名的伙伴(buddy)算法來解決外碎片問題。物理內(nèi)存(ni cn)的分配與回收 共一百六十九頁Linux采用著名的伙伴(Buddy)算法(sun f)來解決外碎片問題伙伴算法把所有的空閑頁面分為10個(gè)塊鏈表,每個(gè)鏈表中的一個(gè)塊含有2的冪次個(gè)頁面(叫做“頁塊”或簡(jiǎn)稱“塊” )例如,第0個(gè)鏈表中塊的大小都是20(1個(gè)頁面),第1個(gè)鏈表中塊的大小都為21(1個(gè)頁面),第9個(gè)鏈表中塊的大小都為29(512個(gè)頁面)伙伴算法采用的是

45、free_area的數(shù)組,定義如下:Struct free_area_structStruct page *next;Struct page *prev;Unsigned int *map; free_area10;頁面(y min)分配與回收算法伙伴算法共一百六十九頁滿足以下條件的兩個(gè)塊稱為伙伴:兩個(gè)塊的大小相同兩個(gè)塊的物理地址連續(xù)伙伴算法把滿足以上條件的兩個(gè)塊合并為一個(gè)塊工作原理:首先在大小滿足要求的塊鏈表中查找是否(sh fu)有空閑塊,若有則直接分配,否則在更大的塊中查找。其逆過程就是塊的釋放,此時(shí)會(huì)把滿足伙伴關(guān)系的塊合并頁面分配與回收(hushu)算法伙伴算法共一百六十九頁例如,假設(shè)

46、(jish)要請(qǐng)求一個(gè)128個(gè)頁框的塊,算法先檢查128個(gè)頁框的鏈表是否有空閑塊,如果沒有則查256個(gè)頁框的鏈表,有則將256個(gè)頁框的塊分裂兩份,一份使用,一份插入128個(gè)頁框的鏈表。如果還沒有,就查512個(gè)頁框的鏈表,有的話就分裂為128,128,256,一個(gè)128使用,剩余兩個(gè)插入對(duì)應(yīng)鏈表。如果在512還沒查到,則返回出錯(cuò)信號(hào)回收過程相反,內(nèi)核試圖把大小為b的空閑伙伴合并為一個(gè)大小為2b的單獨(dú)快,如果成功合并所釋放的塊,會(huì)試圖合并2b的塊來形成更大 的塊。 頁面分配(fnpi)與回收算法伙伴算法共一百六十九頁Linux使用伙伴算法(sun f)有效地分配和回收物理頁塊。該算法(sun f)

47、試圖分配由一個(gè)或多個(gè)連續(xù)物理頁面組成的內(nèi)存塊,其大小為1頁,2頁,或4頁等。只要系統(tǒng)有滿足需要的足夠的空閑頁面,就會(huì)在free_area數(shù)組中查找滿足需要大小的一個(gè)頁塊函數(shù)_get_free_pages 用于分配物理頁塊該函數(shù)所做的工作如下:檢查所請(qǐng)求的頁塊大小是否能夠被滿足檢查系統(tǒng)中空閑物理頁的總數(shù)是否已低于允許的下界正常分配。從free_area數(shù)組的第order項(xiàng)開始,這是一個(gè)mem_map_t鏈表換頁。通過下列語句調(diào)用函數(shù)try_to_free_ pages(),啟動(dòng)換頁進(jìn)程物理(wl)頁面的分配共一百六十九頁1.如果該鏈表中有滿足要求的頁塊,則:將其從鏈表中摘下;將free_area

48、數(shù)組的位圖中該頁塊所對(duì)應(yīng)的位取反,表示頁塊已用;修改全局變量nr_free_pages(減去分配出去的頁數(shù));根據(jù)該頁塊在mem_map數(shù)組中的位置,算出其起始(q sh)物理地址,返回。共一百六十九頁2.如果該鏈表中沒有滿足要求的頁塊,則在free_area數(shù)組中順序向上查找。其結(jié)果有二:a. 整個(gè)free_area數(shù)組中都沒有滿足要求的頁塊,此次無法分配,返回。b. 找到一個(gè)滿足要求的頁塊,則將其從鏈表中摘下;將free_area數(shù)組的位圖中該頁塊所對(duì)應(yīng)的位取反,表示頁塊已用;修改全局變量nr_free_pages(減去分配出去的頁數(shù));因?yàn)轫搲K比申請(qǐng)的頁塊要大,所以要將它分成適當(dāng)大小(d

49、xio)的塊。因?yàn)樗械捻搲K都由2的冪次的頁數(shù)組成,所以這個(gè)分割的過程比較簡(jiǎn)單,只需要將它平分就可以:I. 將其平分為兩個(gè)伙伴,將小伙伴加入free_area數(shù)組中相應(yīng)的鏈表,修改位圖中相應(yīng)的位;II.如果大伙伴仍比申請(qǐng)的頁塊大,則轉(zhuǎn)I,繼續(xù)劃分;III.大伙伴的大小正是所要的大小,修改位圖中相應(yīng)的位,根據(jù)其在mem_map數(shù)組中的位置,算出它的起始物理地址,返回。 共一百六十九頁分配頁塊的過程將大的頁塊劃分為小的頁塊,會(huì)使內(nèi)存更為零散。頁回收(hushu)的過程與頁分配的過程相反,它會(huì)盡可能把小頁塊合并為大頁塊函數(shù)free_pages用于頁塊的回收void free_pages(unsign

50、ed long addr, unsigned long order) addr是要回收的頁塊的首地址,order表示要收回頁塊的大小為2的order次冪個(gè)物理頁物理頁面(y min)的回收共一百六十九頁函數(shù)free_pages所做的工作如下:根據(jù)頁塊的首地址addr算出該塊的第一頁在mem_map數(shù)組的索引(suyn);如果該頁是保留的(內(nèi)核在使用),則不允許回收;將頁塊第一頁對(duì)應(yīng)的mem_map_t結(jié)構(gòu)中的count域減1,表示引用該頁的進(jìn)程數(shù)減了1個(gè)。若count域的值不為0,有別的進(jìn)程在使用該頁塊,不能回收,僅簡(jiǎn)單返回;清除頁塊第一頁對(duì)應(yīng)的mem_map_t結(jié)構(gòu)中flags域的PG_re

51、ferenced位,表示該頁塊不再被引用;將全局變量nr_free_pages的值加上回收的物理頁數(shù)將頁塊加入到數(shù)組free_area的相應(yīng)鏈表中 物理頁面(y min)的回收共一百六十九頁將頁塊加入到數(shù)組free_area的相應(yīng)聯(lián)表中時(shí),要加入的鏈表由order參數(shù)指定,即將頁塊加入到free_areaorder鏈表中。加入的過程如下:1)檢查free_areaorder的位圖map,看該頁塊的伙伴是否(sh fu)已在鏈表中。對(duì)大小為2的order冪次的頁塊,假定其開始頁在mem_map數(shù)組中的索引為map_nr,則計(jì)算其伙伴在mem_map數(shù)組中的索引檢查的結(jié)果有二:a. 其伙伴不在鏈表

52、中,說明該頁塊的伙伴還在使用,不需要合并。此時(shí)只需將位圖中該頁塊相應(yīng)的位取反,表示頁塊已經(jīng)自由;將其加入到free_areaorder鏈表的頭部。b. 其伙伴在鏈表中,說明頁塊及其伙伴均獲得自由,可以將它們合并成更大的頁塊。將頁塊的伙伴從鏈表中摘下,將它們?cè)谖粓D中對(duì)應(yīng)的位取反,表示頁塊已不可用;計(jì)算新的大頁塊在mem_map數(shù)組中的索引(頁塊索引和伙伴索引的小者);order+,回到算法開始,將大頁塊加入到數(shù)組free_area的相應(yīng)鏈表中。 物理(wl)頁面的回收共一百六十九頁Slab分配模式在操作系統(tǒng)的運(yùn)作過程中,經(jīng)常會(huì)涉及到大量對(duì)象的重復(fù)生成、使用和釋放問題。對(duì)象生成算法的改進(jìn),可以在很

53、大程度上提高整個(gè)系統(tǒng)的性能。在Linux系統(tǒng)中所用到的對(duì)象,比較典型的例子是inode、task_struct等, 都又這些特點(diǎn)。一般,這類對(duì)象的種類相對(duì)穩(wěn)定,每種對(duì)象的數(shù)量卻是巨大的,并且在初始化與析構(gòu)時(shí)要做大量的工作,所占用的時(shí)間遠(yuǎn)遠(yuǎn)超過(chogu)內(nèi)存分配的時(shí) 間。但是這些對(duì)象往往具有這樣一個(gè)性質(zhì),即他們?cè)谏蓵r(shí),所包括的成員屬性值一般都賦成確定的數(shù)值,并且在使用完畢,釋放結(jié)構(gòu)前,屬性又恢復(fù)為未使用 前的狀態(tài)。因此,如果我們能夠用合適的方法使得在對(duì)象前后兩次被使用時(shí),在同一塊內(nèi)存,或同一類內(nèi)存空間,且保留了基本的數(shù)據(jù)結(jié)構(gòu),就可以大大提高效率。slab算法就是針對(duì)上述特點(diǎn)設(shè)計(jì)的。共一百六

54、十九頁Slab分配模式單單分配頁面的分配器肯定是不能滿足要求的 內(nèi)核中大量使用各種數(shù)據(jù)結(jié)構(gòu),大小從幾個(gè)字節(jié)到幾十上百k不等,都取整到2的冪次個(gè)頁面那是完全不現(xiàn)實(shí)的 早期內(nèi)核的解決方法是提供大小為2, 4, 8, 16, ., 131056字節(jié)的內(nèi)存區(qū)域 需要新的內(nèi)存區(qū)域時(shí),內(nèi)核從伙伴(hubn)系統(tǒng)申請(qǐng)頁面,把它們劃分成一個(gè)個(gè)區(qū)域,取一個(gè)來滿足需求 如果某個(gè)頁面中的內(nèi)存區(qū)域都釋放了,頁面就交回到伙伴系統(tǒng) 共一百六十九頁但這種分配方法有許多值得改進(jìn)的地方:不同的數(shù)據(jù)類型用不同的方法分配內(nèi)存可能提高效率。比如需要初始化的數(shù)據(jù)結(jié)構(gòu),釋放后可以暫存著,再分配時(shí)就不必初始化了 內(nèi)核的函數(shù)常常重復(fù)地使用同

55、一類型的內(nèi)存區(qū),緩存最近釋放的對(duì)象可以加速分配和釋放 對(duì)內(nèi)存的請(qǐng)求可以按照請(qǐng)求頻率來分類,頻繁使用的類型使用專門的緩存,很少使用的可以使用通用緩存使用2的冪次大小的內(nèi)存區(qū)域時(shí)硬件高速緩存沖突的概率較大,有可能通過仔細(xì)安排內(nèi)存區(qū)域的起始地址來減少(jinsho)硬件高速緩存沖突 緩存一定數(shù)量的對(duì)象可以減少對(duì)buddy系統(tǒng)的調(diào)用,從而節(jié)省時(shí)間并減少由此引起的硬件高速緩存污染 共一百六十九頁Slab機(jī)制提出的原因:為了減少對(duì)伙伴算法的調(diào)用次數(shù) 內(nèi)核經(jīng)常反復(fù)使用某一內(nèi)存區(qū) 內(nèi)存區(qū)可根據(jù)其使用頻率(pnl)來分類 硬件高速緩存的使用,為盡量減少對(duì)伙伴算法的調(diào)用提供了另一個(gè)理由Slab 分配(fnpi)機(jī)

56、制分配(fnpi)小內(nèi)存共一百六十九頁slab分配器slab分配器體現(xiàn)了這些改進(jìn)思想slab分配器把內(nèi)存區(qū)看成對(duì)象slab分配器把對(duì)象分組放進(jìn)高速緩存。每個(gè)高速緩存都是同種類型內(nèi)存對(duì)象的一種“儲(chǔ)備”例如當(dāng)一個(gè)文件被打開時(shí),存放相應(yīng)“打開文件”對(duì)象所需的內(nèi)存是從一個(gè)叫做filp(file pointer)的slab分配器的高速緩存中得到(d do)的也就是說每種對(duì)象類型對(duì)應(yīng)一個(gè)高速緩存共一百六十九頁Slab分配模式把對(duì)象分組放進(jìn)緩沖區(qū) Slab緩沖區(qū)由一連串的“大塊(d kui)(Slab)”構(gòu)成,每個(gè)大塊中包含若干個(gè)同種類型的對(duì)象,這些對(duì)象或已被分配,或空閑 簡(jiǎn)言之,緩沖區(qū)就是主存中的一片區(qū)域

57、,把這片區(qū)域劃分為多個(gè)塊,每塊就是一個(gè)Slab,每個(gè)Slab由一個(gè)或多個(gè)頁面組成,每個(gè)Slab中存放的就是對(duì)象 Slab 分配(fnpi)機(jī)制分配(fnpi)小內(nèi)存共一百六十九頁每個(gè)高速緩存被分成多個(gè)(du )slabs,每個(gè)slab由一個(gè)或多個(gè)(du )連續(xù)的頁框組成,其中包含一定數(shù)目的對(duì)象共一百六十九頁每個(gè)slab有三種狀態(tài):全滿,半滿,全空全滿意味著slab中的對(duì)象全部已被分配出去全空意味著slab中的對(duì)象全部是可用的半滿介于兩者之間當(dāng)內(nèi)核函數(shù)需要一個(gè)新的對(duì)象時(shí),優(yōu)先從半滿的slab滿足這個(gè)請(qǐng)求否則從全空的slab中取一個(gè)對(duì)象滿足請(qǐng)求如果(rgu)沒有空的slab則向buddy系統(tǒng)申請(qǐng)頁

58、面生成一個(gè)新的slab共一百六十九頁專用緩沖區(qū)主要用于頻繁使用的數(shù)據(jù)結(jié)構(gòu),如task_struct、mm_struct、vm_area_struct、file、dentry、inode等緩沖區(qū)是用kmem_cache_t類型描述的,通過kmem_cache_create()來建立 函數(shù)kmem_cache_create()所創(chuàng)建的緩沖區(qū)中還沒有包含(bohn)任何Slab,因此,也沒有空閑的對(duì)象。只有以下兩個(gè)條件都為真時(shí),才給緩沖區(qū)分配Slab:已發(fā)出一個(gè)分配新對(duì)象的請(qǐng)求;緩沖區(qū)不包含任何空閑對(duì)象; Slab專用緩沖區(qū)的建立(jinl)和釋放 共一百六十九頁在內(nèi)核中初始化開銷不大的數(shù)據(jù)結(jié)構(gòu)(s

59、h j ji u)可以合用一個(gè)通用的緩沖區(qū)通用緩沖區(qū)類似于物理頁面分配中的大小分區(qū),最小的為32字節(jié),然后依次為64、128,直至128KB(即32個(gè)頁面)對(duì)通用緩沖區(qū)的管理采用Slab方式當(dāng)一個(gè)數(shù)據(jù)結(jié)構(gòu)的使用不頻繁、或其大小不足一個(gè)頁面時(shí),沒有必要給其分配專用緩沖區(qū) ,可調(diào)用函數(shù)kmallo() 分配通用緩沖區(qū)。如果數(shù)據(jù)結(jié)構(gòu)的大小接近一個(gè)頁面,則可通過調(diào)用_get_free_page()為止分配一個(gè)頁面通用(tngyng)緩沖區(qū)共一百六十九頁從通用緩沖區(qū)中分配和釋放緩沖區(qū)的函數(shù)為:void *kmalloc(size_t size, int flags);Void kree(const vo

60、id *objp); 事實(shí)上,在內(nèi)核中,尤其是驅(qū)動(dòng)程序中,有大量的數(shù)據(jù)結(jié)構(gòu)僅僅是一次性使用,而且所占內(nèi)存只有幾十個(gè)字節(jié),因此,一般調(diào)用kmalloc()給內(nèi)核數(shù)據(jù)結(jié)構(gòu)分配內(nèi)存就足夠另外,因?yàn)樵贚inux2.0以前的版本一般都調(diào)用kmallo()給內(nèi)核數(shù)據(jù)結(jié)構(gòu)分配內(nèi)存,因此,調(diào)用該函數(shù)的一個(gè)優(yōu)點(diǎn)是讓你開發(fā)的驅(qū)動(dòng)程序能保持向后兼容kfree()函數(shù)釋放由kmalloc()分配出來的內(nèi)存塊。如果想要釋放的內(nèi)存不是由kmalloc()分配的,或者想要釋放的內(nèi)存早就被釋放過了,比如說釋放屬于內(nèi)核其它部分的內(nèi)存,調(diào)用這個(gè)函數(shù)會(huì)導(dǎo)致嚴(yán)重(ynzhng)的后果通用(tngyng)緩沖區(qū)共一百六十九頁任何(rn

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論