第4章-內(nèi)存管理_第1頁
第4章-內(nèi)存管理_第2頁
第4章-內(nèi)存管理_第3頁
第4章-內(nèi)存管理_第4頁
第4章-內(nèi)存管理_第5頁
已閱讀5頁,還剩133頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第四章內(nèi)存管理內(nèi)存管理內(nèi)存管理子系統(tǒng)是操作系統(tǒng)的重要組成部分,它的主要任務(wù)是:管理系統(tǒng)中的內(nèi)存資源,提供高效地分配和回收內(nèi)存資源的手段;提高內(nèi)存的利用率,減少對內(nèi)存的浪費,充分發(fā)揮內(nèi)存的作用。Linux共實現(xiàn)了五個內(nèi)存管理器,它們是:物理內(nèi)存管理器內(nèi)核內(nèi)存管理器虛擬內(nèi)存管理器內(nèi)核虛擬內(nèi)存管理器用戶空間內(nèi)存管理器內(nèi)存管理內(nèi)核內(nèi)存管理器虛擬內(nèi)存管理器內(nèi)核虛擬內(nèi)存管理器物理內(nèi)存管理器用戶內(nèi)存管理器物理內(nèi)存系統(tǒng)其余部分4.1物理內(nèi)存管理器物理內(nèi)存管理器管理的基本內(nèi)存單位是物理頁,每個物理頁用一個page結(jié)構(gòu)描述,所有的page結(jié)構(gòu)組成一個mem_map[]數(shù)組。typedefstructpage{ structpage *next; structpage *prev; structinode *inode; unsignedlong offset; structpage *next_hash; //用于頁緩存 atomic_t count; unsignedlong flags; structwait_queue *wait; structpage **pprev_hash; //用于頁緩存 structbuffer_head *buffers;}mem_map_t;4.1物理內(nèi)存管理器flags各位的意義位名稱意義0PG_locked加鎖1PG_error頁上出現(xiàn)I/O錯2PG_referenced正被引用3PG_dirty臟頁4PG_uptodate頁的內(nèi)容是否有效5PG_free_after頁已寫完8PG_DMA能否用作DMA傳送9PG_Slab是否用做slab(內(nèi)核內(nèi)存管理器)31PG_reserved1:保留,0:可用4.1物理內(nèi)存管理器系統(tǒng)中所有的空閑頁都記錄在數(shù)組free_area[]中。structfree_area_struct{ structpage*next; structpage*prev; unsignedint*map;};structfree_area_structfree_area[NR_MEM_LISTS];NR_MEM_LISTS的值是10或12。該數(shù)組已經(jīng)建立并初始化。4.1物理內(nèi)存管理器位圖map用于記錄頁塊及其伙伴是否在隊列中,兩個伙伴合用一位,其意義如下:1)如兩伙伴全都不在隊列中(已分配或已組成了更大的塊),它們合用的位為0;2)如一個伙伴在隊列中,一個不在隊列中,則它們合用的位為1;3)如兩個伙伴都在隊列中,則它們應(yīng)該合并成更大的塊,加入到free_area[]數(shù)組中更上面的隊列,所以它們合用的位應(yīng)為0;4)在free_area數(shù)組的最大一個隊列中,位圖無用。位圖的大小=物理頁數(shù)/2i位,i是隊列在數(shù)組free_area[]中的索引。(應(yīng)該是物理頁數(shù)/2(i+1))。4.1物理內(nèi)存管理器用第一個物理頁的page結(jié)構(gòu)代表大小為2i頁的連續(xù)物理頁塊,用它的編號代表整個頁塊的編號。大小為2i、編號為map_nr的頁塊的伙伴是:map_nr^(-((~0)<<i))這兩個伙伴在位圖free_area[i]->map中共用的標(biāo)志位是:(map_nr)>>(1+i)如:頁塊8、9、10、11(代表是8)的伙伴是12、13、14、15(代表是12),它們在位圖free_area[2]->map中共用第1位。4.1物理內(nèi)存管理器04321765物理內(nèi)存……3210mapmapmapmap4561free_area[]4.1物理內(nèi)存管理器物理內(nèi)存管理器使用向量表free_area[]來分配和回收物理頁。

全局變量nr_free_pages記錄系統(tǒng)中當(dāng)前的空閑頁數(shù)。全局變量freepages為系統(tǒng)中的空閑物理內(nèi)存劃了三條基準(zhǔn)線。typedefstructfreepages_v1{ unsignedint min; unsignedint low; unsignedint high;}freepages_v1;typedeffreepages_v1 freepages_t;freepages_t freepages;

4.1物理內(nèi)存管理器分配原則(該原則在不斷變化):當(dāng)系統(tǒng)中空閑物理頁數(shù)少于freepages.min時,應(yīng)該回收內(nèi)存;一旦開始內(nèi)存回收,每次分配前都要進(jìn)行回收,直到系統(tǒng)中空閑物理頁數(shù)大于freepages.high;當(dāng)系統(tǒng)中空閑物理頁數(shù)大于freepages.high時,每次都直接進(jìn)行內(nèi)存分配,直到空閑物理頁數(shù)再次小于freepages.min;當(dāng)系統(tǒng)中空閑內(nèi)存數(shù)大于freepages.high時,可以立刻進(jìn)行內(nèi)存分配。4.1.2物理頁分配物理內(nèi)存管理器使用伙伴(Buddy)算法分配和釋放物理頁塊,頁塊大小為2i個頁。物理內(nèi)存管理器返回的是在內(nèi)核空間中看到的內(nèi)存塊的起始地址(物理地址+0xC0000000)。物理內(nèi)存的分配和釋放不影響頁目錄和頁表。分配函數(shù)是__get_free_pages,定義為:unsignedlong__get_free_pages(intgfp_mask,unsignedlongorder)gfp_mask是對內(nèi)存的要求,order是申請的大小(2的指數(shù))。4.1.2物理頁分配1、如果空閑物理內(nèi)存較少(需要回收),則:1)喚醒內(nèi)核交換守護(hù)進(jìn)程kswapd。2)如果在gfp_mask中設(shè)置了__GFP_WAIT標(biāo)志,則強(qiáng)行回收內(nèi)存(自己調(diào)用回收函數(shù))。2、如果不需要回收內(nèi)存或已回收到了足夠的內(nèi)存,則查free_area數(shù)組的第order列:如果其中有滿足要求的頁塊,則摘下一塊,修改位圖,累減nr_free_pages,返回物理頁塊的首地址。否則(隊列為空),向上搜索free_area數(shù)組:如果整個free_area數(shù)組中都沒有滿足要求的頁塊,則此次分配失敗,返回0。如果找到了一個滿足要求的頁塊,則將其從隊列中摘下、反復(fù)分割成伙伴,將一個大小適中的伙伴分配給用戶,其余伙伴加入free_area數(shù)組。同時修改位圖,累減變量nr_free_pages。4.1.2物理頁分配04321765物理內(nèi)存……3210mapmapmapmap456free_area申請1頁4.1.2物理頁分配04321765物理內(nèi)存……3210mapmapmapmap4、5566free_area4.1.3物理頁釋放在物理頁的釋放過程中,必須盡可能地按照伙伴算法合并頁塊。函數(shù)free_pages用于釋放頁塊,其定義如下:

voidfree_pages(unsignedlongaddr,unsignedlongorder)

addr是要釋放頁塊的首地址;order是要釋放頁塊的大小。4.1.3物理頁釋放1、根據(jù)首地址addr算出頁塊在mem_map[]中的索引map_nr(addr>>12),找到頁塊第一頁對應(yīng)的page結(jié)構(gòu)(mem_map[map_nr])。2、如果該頁塊是保留的,則不允許釋放,返回。3、將page結(jié)構(gòu)的引用計數(shù)(page.count)減1。4、如果count>0,說明頁塊還有別的使用者,因此不能釋放它。返回。4.1.3物理頁釋放5、如果count=0,則釋放它:1)清除page結(jié)構(gòu)的flags域中的PG_referenced位。2)累加變量nr_free_pages(加上回收的物理頁數(shù))。3)將頁塊加入到數(shù)組free_area[]中:如果頁塊的伙伴不在隊列free_area[order]中,則將其直接插入隊列,修改位圖。返回。如果頁塊的伙伴在隊列中且order=NR_MEM_LISTS-1,則將其直接插入隊列。返回。如果頁塊的伙伴在隊列中但order<NR_MEM_LISTS-1,則將頁塊的伙伴從隊列中摘下、修改位圖,將它們合并成一個更大的頁塊,重新插入數(shù)組free_area[]中(遞歸)。4.1.3物理頁釋放04321765物理內(nèi)存……3210mapmapmapmap4、5566free_area4.1.4物理頁回收內(nèi)核交換守護(hù)進(jìn)程kswapd負(fù)責(zé)物理頁的回收,從而保證系統(tǒng)有足夠的空閑頁。其主體如下:while(1){ do{ if(nr_free_pages>=freepages.high) break; //不需要回收內(nèi)存 if(!do_try_to_free_pages(GFP_KSWAPD)) break; //沒有回收到內(nèi)存 }while(!tsk->need_resched); run_task_queue(&tq_disk); //處理磁盤任務(wù)隊列 tsk->state=TASK_INTERRUPTIBLE; schedule_timeout(HZ); //睡眠100個滴答}4.1.4物理頁回收在函數(shù)do_try_to_free_pages中完成物理頁的回收工作。為了提高效率,該函數(shù)要嘗試多種回收手段,一次回收多個物理頁(SWAP_CLUSTER_MAX==32)。

為了公平起見,該函數(shù)采用時鐘算法搜索各種數(shù)據(jù)結(jié)構(gòu)。不是每次都從頭開始,也不是每次都檢查完所有的結(jié)構(gòu)。每次檢查的數(shù)據(jù)結(jié)構(gòu)的個數(shù)由對物理內(nèi)存的需求決定。如果系統(tǒng)中的空閑頁太少,就多檢查一些,否則就少檢查一些。4.1.4物理頁回收函數(shù)do_try_to_free_pages回收內(nèi)存的順序如下:1、從內(nèi)核內(nèi)存管理器中回收空閑頁。

kmem_cache_reap(gfp_mask)

2、回收可廢棄的內(nèi)存頁。

shrink_mmap(priority,gfp_mask)

順序搜索數(shù)組mem_map[],回收:在交換緩存中且已經(jīng)不再使用的頁。用作buffer且所有buffer都不再使用的頁。在頁緩存中且沒有任何進(jìn)程使用的頁。4.1.4物理頁回收3、回收共享內(nèi)存頁。

shm_swap(priority,gfp_mask)

4、回收進(jìn)程的虛擬內(nèi)存,即將進(jìn)程的某些頁交換到外存。

swap_out(priority,gfp_mask)

5、從目錄緩存中回收物理頁。

shrink_dcache_memory(priority,gfp_mask)

4.1物理內(nèi)存管理器當(dāng)物理內(nèi)存較大時(超過1GB),上述方法需要擴(kuò)充,為此引入zone的概念:zone是具有相同屬性的連續(xù)的物理頁。通常定義三個zone:1、ZONE_DMA:16MB以內(nèi),用于DMA。2、ZONE_NORMAL:16MB~896MB,用于普通物理內(nèi)存,在內(nèi)核中有虛擬地址。3、ZONE_HIGHMEM:大于896MB,用于高端物理內(nèi)存,在內(nèi)核中沒有虛擬地址。每個zone都有自己的free_area[]數(shù)組。4.1物理內(nèi)存管理器隨著NUMA結(jié)構(gòu)的出現(xiàn),系統(tǒng)所管理的物理地址空間不再一致。對一個CPU來說,有的內(nèi)存近,有的內(nèi)存遠(yuǎn);有的速度快,有的速度慢。CPU希望使用盡可能一致的物理頁,尤其是對一次申請。為此引入節(jié)點(node)的概念。節(jié)點的描述結(jié)構(gòu)是pglist_data,其中定義了該節(jié)點的管理區(qū)(zone)、各類需求(GFP標(biāo)志)的分配策略(每策略最多有4個可選的zone,它們按優(yōu)先級排序,分配時按順序搜索各zone并試圖從中分配物理頁)、其page結(jié)構(gòu)數(shù)組等。系統(tǒng)中所有的節(jié)點組成一個隊列pgdat_list。

4.2內(nèi)核內(nèi)存管理器內(nèi)核在運行的過程中,需要大量而頻繁地使用內(nèi)存,如建立各種用于管理的數(shù)據(jù)結(jié)構(gòu)、緩沖區(qū)等。這些內(nèi)存有以下特點:尺寸一般都很小,遠(yuǎn)遠(yuǎn)小于一頁,如果直接使用物理內(nèi)存管理器按頁管理,其利用率會非常低。要求動態(tài)分配和釋放,無法預(yù)測使用量。不參與交換(不在進(jìn)程的虛擬地址空間,也不在交換緩存、頁緩存及Buffercache中,不會被換入、換出)。要求響應(yīng)速度快,分配速度慢的管理器會導(dǎo)致整個系統(tǒng)性能的下降。4.2內(nèi)核內(nèi)存管理器內(nèi)核內(nèi)存管理器的種類:1、無內(nèi)核內(nèi)存管理器;2、資源映射圖分配器;3、簡單2次冪空閑表;4、McKusick-Karels分配器;5、伙伴系統(tǒng);6、SVR4Lazy伙伴算法;7、Mach-OSF/1的Zone分配器;8、存儲桶(bucket);9、Solaris2.4的Slab分配器。Linux的內(nèi)核內(nèi)存管理器采用Slab分配器。4.2內(nèi)核內(nèi)存管理器cache_cachecache1cache2cache3……cachenslab1slab2slab3slab4s_freep物理頁對象對象對象對象4.2內(nèi)核內(nèi)存管理器(cache結(jié)構(gòu))structkmem_cache_s{ kmem_slab_t *c_freep; //第一個有空閑對象的slab unsignedlong c_flags; //標(biāo)志 unsignedlong c_offset; unsignedlong c_num; //每個slab中的對象數(shù) unsignedlong c_magic; unsignedlong c_inuse; //keptatzero kmem_slab_t *c_firstp; //第一個slab kmem_slab_t *c_lastp; //最后一個slab spinlock_t c_spinlock; unsignedlong c_growing; //是否正在增長 unsignedlong c_dflags; size_t c_org_size; //對象原始大小 unsignedlong c_gfporder; //表示slab大小的指數(shù) void(*c_ctor)(void,kmem_cache_t,unsignedlong); //構(gòu)造函數(shù) void(*c_dtor)(void,kmem_cache_t,unsignedlong); //析構(gòu)函數(shù) unsignedlong c_align; //對象對齊關(guān)系 size_t c_colour; //cache著色區(qū)的大小 size_t c_colour_next; //著色區(qū)中下一個可用的位置 unsignedlong c_failures; constchar *c_name; //cache名 structkmem_cache_s*c_nextp; //下一個cache結(jié)構(gòu) kmem_cache_t *c_index_cachep; //分配slab->s_index數(shù)組的cache};4.2內(nèi)核內(nèi)存管理器(cache結(jié)構(gòu))該結(jié)構(gòu)描述了一個cache的所有信息,如:一個slab的大?。ㄕ级嗌傥锢眄摚篶_gfporder;slab中一個對象的大?。篶_org_size;一個slab可以劃分成多少對象:c_num;該cache所管理的第一個slab、最后一個slab和第一個有空閑對象的slab:c_firstp、c_lastp、c_freep;著色區(qū):剩余空間,用于均勻分布slab對象。域c_offset的意義隨slab對象的大小而變化:對小對象:它是從對象起始地址到對象指針kmem_bufctl_s之間的距離;對大對象:它是對象的大小。4.2內(nèi)核內(nèi)存管理器(slab結(jié)構(gòu))#define SLAB_OFFSET_BITS 16 typedefstructkmem_slab_s{ structkmem_bufctl_s *s_freep; //第一個空閑對象 structkmem_bufctl_s *s_index; //大對象指針數(shù)組 unsignedlong s_magic; unsignedlong s_inuse; //已用的對象數(shù) structkmem_slab_s *s_nextp; structkmem_slab_s *s_prevp; void *s_mem; //第一個對象的地址 unsignedlong s_offset:SLAB_OFFSET_BITS, s_dma:1; //能否用做DMA}kmem_slab_t;4.2內(nèi)核內(nèi)存管理器(slab結(jié)構(gòu))結(jié)構(gòu)kmem_slab_s描述了一個slab的所有信息,如:第一個對象的地址:s_mem;指向第一個空閑對象的指針:s_freep;slab中已經(jīng)用掉的對象數(shù):s_inuse;對象可否用于DMA等。slab結(jié)構(gòu)所在的位置與對象大小有關(guān):小對象(<512字節(jié)):與對象在同一個物理頁塊上;大對象(≥512字節(jié)):在物理頁塊之外。目的是盡可能地減少內(nèi)存的浪費。專門定義一個slabcache,用于管理slab結(jié)構(gòu)的分配和回收。4.2內(nèi)核內(nèi)存管理器(slab結(jié)構(gòu))每一個小對象的尾部都加了一個kmem_bufctl_s結(jié)構(gòu),用于管理小對象。typedefstructkmem_bufctl_s{ union{ structkmem_bufctl_s *buf_nextp; kmem_slab_t *buf_slabp; void *buf_objp; }u;}kmem_bufctl_t;kmem_bufctl_s結(jié)構(gòu)可以用作不同目的,如分配前用它將slab對象連接成鏈表,分配后用它指向?qū)ο笏鶎俚膕lab結(jié)構(gòu)等。2.4以后,該結(jié)構(gòu)已經(jīng)退化成一個無符號小整數(shù)。4.2內(nèi)核內(nèi)存管理器(通用cache)系統(tǒng)初始化時,預(yù)定義了14個通用cache,并已將它們的cache結(jié)構(gòu)保存在數(shù)組cache_sizes[]中。typedefstructcache_sizes{ size_t cs_size; kmem_cache_t *cs_cachep;}cache_sizes_t;cache_sizes_tcache_sizes[14];32641282565121024204840968192163843276865536131072cachecachecachecachecachecache_sizes[]4.2.2cache的建立kmem_cache_t*kmem_cache_create(constchar*name, size_tsize,size_toffset,unsignedlongflags, void(*ctor)(void*,kmem_cache_t*,unsignedlong), void(*dtor)(void*,kmem_cache_t*,unsignedlong))完成如下工作:1、檢查各參數(shù)的合法性。

2、從cache_cache中申請一個內(nèi)存塊用于建立新cache的kmem_cache_s結(jié)構(gòu)。

3、計算并填寫新cache結(jié)構(gòu)的各個域。4、將新cache的結(jié)構(gòu)插入系統(tǒng)中的cache鏈表中。4.2.3為cache增加slabintkmem_cache_grow(kmem_cache_t*cachep,intflags)完成如下工作:1、從物理內(nèi)存管理器中申請物理頁,頁數(shù)由cache結(jié)構(gòu)中的c_gfporder域指定。2、建立slab結(jié)構(gòu):小對象,在物理頁的尾部(或首部)建立slab結(jié)構(gòu);大對象,在cache_slabp中申請一個slab結(jié)構(gòu)。3、對大對象cache,再申請一塊內(nèi)存用于建立slab對象鏈表(kmem_bufctl_t結(jié)構(gòu)數(shù)組)。slab的s_index域指向該結(jié)構(gòu)數(shù)組。4.2.3為cache增加slab4、修改申請到的各物理頁(不僅是第一頁)的page結(jié)構(gòu):next指向kmem_cache_s結(jié)構(gòu),prev指向kmem_slab_s結(jié)構(gòu)(便于對象的釋放);在域flags上加入PG_Slab標(biāo)志。5、初始化slab結(jié)構(gòu)及各slab對象。小對象:將各slab對象串成鏈表,讓s_freep指向表頭。大對象:將結(jié)構(gòu)數(shù)組s_index的各元素串成鏈表,讓s_freep指向表頭。6、將新slab加入cachep中,同時調(diào)整cachep的c_freep、c_firstp、c_lastp指針。4.2.3為cache增加slabslab結(jié)構(gòu)s_indexs_freeps_memkmem_bufctl_t結(jié)構(gòu)數(shù)組大對象cache的slab結(jié)構(gòu)物理頁塊對象對象對象對象4.2.3為cache增加slabs_freepkmem_bufctl_t著色區(qū)Slab結(jié)構(gòu)……小對象cache的slab結(jié)構(gòu)

小對象小對象小對象4.2.4對象的分配有兩種對象分配函數(shù):kmalloc(size_tsize,intflags)kmem_cache_alloc(kmem_cache_t*cachep,intflags)當(dāng)只知大小不知cache時用第一個,知道cache時用第二個。kmalloc先根據(jù)size在cache_sizes[]中找到一個通用cache,而后再從cache中分配對象。從cache中分配對象的方法如下:1、如果還未為cache創(chuàng)建slab,或它的所有slab都沒有空閑對象,則調(diào)用函數(shù)kmem_cache_grow()為其創(chuàng)建一個新的slab。4.2.4對象的分配2、找出該cache中有空閑對象的第一個slab,并找到它的第一個空閑對象(s_freep)。將第一個空閑對象分配出去(bufp),并調(diào)整slab的參數(shù)。3、返回空閑對象的首地址: 1)小對象: objp=((void*)bufp)-cachep->c_offset; //地址 bufp->buf_slabp=slabp; //指向它所屬的slab 2)大對象: objp=((bufp-slabp->s_index)*cachep->c_offset) +slabp->s_mem; bufp->buf_objp=objp;4.2.5對象的釋放三種釋放操作:1、知道對象所屬cache時,用:kmem_cache_free(kmem_cache_t*cachep,void*objp)2、不知對象所屬cache時,用:kfree(constvoid*objp)1)mem_map[objp>>12]是objp所在物理頁的page2)(kmem_cache_t*)(>next)是該頁對應(yīng)的cache結(jié)構(gòu)3、知道對象大小時,用:kfree_s(constvoid*objp,size_tsize)增加一個大小檢查。4.2.5對象的釋放(小對象)1、利用對象尾部的指針找到它所屬的slab。 bufp=(kmem_bufctl_t*)(objp+cachep->c_offset); slabp=bufp->buf_slabp;2、將對象加入slab的空閑對象隊列中。3、調(diào)整cache的空閑隊列:1)如果釋放以后slab全部空閑,將該slab移到slab隊列的隊尾,以便歸還給物理內(nèi)存管理器。2)如果釋放以前slab已被全部分完,則將該slab后移,以保證slab隊列的順序,必要時調(diào)整cache的c_freep指針。4.2.5對象的釋放(大對象)1、根據(jù)對象地址objp,找到對象所在的物理頁,并據(jù)此找到該對象所屬的slab:slabp=(kmem_slab_t*)(mem_map[objp>>12].prev);2、算出該對象在指針數(shù)組中的位置:slabp->s_index[(objp-slabp->s_mem)/cachep->c_offset]3、將對象加入slab的空閑對象隊列中。1)如果釋放以后slab全部空閑,則將該slab移到隊尾。2)如果釋放以前slab已被全部分完,則將該slab后移,必要時調(diào)整cache的c_freep指針。4.2.6回收cache中的空閑slab函數(shù)kmem_cache_reap按照時鐘算法,每次搜索10個cache,從中選擇一個空閑slab最多的cache,將它的空閑slab歸還給物理內(nèi)存管理器。

1、從clock_searchp開始順序搜索各cache,找出一個空閑slab最多的cache。

2、調(diào)整clock_searchp,使其指向找到的cache。3、回收該cache的空閑slab。下列cache不在回收之列:標(biāo)志為SLAB_NO_REAP的cache正在增長的cache已經(jīng)損壞的cache不滿足要求的cache4.3虛擬內(nèi)存管理器直接使用物理內(nèi)存管理器可以運行程序,方法是:申請足夠的內(nèi)存,將程序一次性全部裝入。但可能帶來如下問題:1、當(dāng)程序過大時(超過可用的物理內(nèi)存量),無法將其裝入內(nèi)存,因而無法運行。2、多進(jìn)程并發(fā)執(zhí)行的開銷很大(需要將進(jìn)程整個或部分地?fù)Q出/換入內(nèi)存)。3、由于直接使用物理內(nèi)存,因而進(jìn)程之間難以實現(xiàn)隔離和保護(hù)。4、程序的設(shè)計依賴于物理內(nèi)存的配置,編程困難且程序難以移植。4.3虛擬內(nèi)存管理器但大程序、多進(jìn)程、并發(fā)、保護(hù)、移植等是現(xiàn)代軟件設(shè)計不可回避的問題,因而是操作系統(tǒng)必須解決的問題。人們提出了很多方法來解決上述問題,如覆蓋、交換,但這兩種技術(shù)都不能完全滿足需要。軟件覆蓋技術(shù):通過覆蓋那些暫時不用的程序代碼或數(shù)據(jù)來復(fù)用內(nèi)存。

交換機(jī)制:進(jìn)程被作為一個完整的單位,在內(nèi)存和外存之間交換。4.3虛擬內(nèi)存管理器為此又提出了基于分頁機(jī)制的虛擬內(nèi)存管理,其思路是:虛擬(欺騙),即給用戶進(jìn)程造成系統(tǒng)有大內(nèi)存,而且它獨占大內(nèi)存的假象。方法:1、隔離:不讓用戶進(jìn)程看到實際的物理內(nèi)存,只給它看到一個美好的假象(虛擬內(nèi)存)。2、勤快:頻繁地在內(nèi)、外存之間移動數(shù)據(jù),保證進(jìn)程當(dāng)前使用到的代碼和數(shù)據(jù)在內(nèi)存中。3、小單位:量小、速度快,不易被察覺。規(guī)律:程序運行的局部性規(guī)律。4.3虛擬內(nèi)存管理器1978年,Unix系統(tǒng)在VAX機(jī)上第一次實現(xiàn)了基于分頁機(jī)制的虛擬內(nèi)存管理器:1、將物理地址空間和程序的虛擬地址空間都分成固定大小的頁,同時引入頁表,實現(xiàn)虛擬空間與物理空間的隔離,并負(fù)責(zé)虛擬地址到物理地址的轉(zhuǎn)換。2、地址的轉(zhuǎn)換由硬件實現(xiàn),轉(zhuǎn)換所用的頁表由操作系統(tǒng)內(nèi)核維護(hù)。3、虛擬內(nèi)存管理器負(fù)責(zé)在內(nèi)外存之間交換頁面,給用戶造成假象,使得每個進(jìn)程都認(rèn)為自己是系統(tǒng)中唯一的一個程序,獨占系統(tǒng)的全部地址空間(4GB)。分頁機(jī)制、頁表、虛擬內(nèi)存的引入,是操作系統(tǒng)發(fā)展史上一個里程碑。4.3虛擬內(nèi)存管理器OS程序邏輯地址空間物理地址空間頁表交換外存搬入搬出搬入4.3虛擬內(nèi)存管理器虛擬內(nèi)存管理器的優(yōu)點(設(shè)計目標(biāo)):1、大地址空間:進(jìn)程可用的地址空間可超過物理內(nèi)存總量。2、并發(fā):允許多進(jìn)程同時駐留內(nèi)存。3、進(jìn)程保護(hù):不同進(jìn)程的虛擬地址空間完全隔離。4、虛存共享:不同進(jìn)程之間可以共享物理頁。5、代碼可移植:在設(shè)計程序時不必預(yù)先約定機(jī)器的配置。6、內(nèi)存映射:將文件映射到進(jìn)程的虛擬地址空間,使得對文件的訪問與對內(nèi)存單元的訪問一樣。7、允許程序重定位:程序可以放在物理內(nèi)存中的任意位置,且可以在執(zhí)行過程中任意移動。8、代價?。簱Q入換出單個頁面的代價比交換整個進(jìn)程或內(nèi)存段要小得多。4.3虛擬內(nèi)存管理器虛擬內(nèi)存管理器的功能:1、地址空間管理:負(fù)責(zé)進(jìn)程虛擬地址空間的創(chuàng)建、回收和動態(tài)改變。2、地址轉(zhuǎn)換:將進(jìn)程產(chǎn)生的虛擬地址轉(zhuǎn)換為物理地址。當(dāng)無法轉(zhuǎn)換時,產(chǎn)生缺頁異常。(硬件和內(nèi)核共同完成)3、缺頁處理:當(dāng)產(chǎn)生缺頁異常時,把需要的頁面裝入內(nèi)存。4、換出:當(dāng)物理內(nèi)存緊缺時,將進(jìn)程的某些頁面換出內(nèi)存。5、內(nèi)存保護(hù):以頁為單位實現(xiàn)內(nèi)存的保護(hù)。當(dāng)發(fā)現(xiàn)非法地址訪問時,向進(jìn)程發(fā)送段違例信號(SIGSEGV)。6、內(nèi)存共享:允許別的進(jìn)程共享其地址空間的某一部分。7、監(jiān)視系統(tǒng)負(fù)荷:當(dāng)系統(tǒng)超負(fù)荷時,采取相應(yīng)措施,如停止啟動新進(jìn)程等。8、其它服務(wù):提供對其它功能的支持,如文件映射、動態(tài)連接庫等。4.3虛擬內(nèi)存管理器幾個概念: 裝入 執(zhí)行程序地址 進(jìn)程地址 機(jī)器地址 描述符 頁表邏輯地址 線性地址 物理地址

(虛擬地址)

邏輯地址空間 線性地址空間 物理地址空間

(虛擬地址空間)4.3.1虛擬內(nèi)存抽象模型(頁表)在虛擬內(nèi)存管理結(jié)構(gòu)中,頁表是最關(guān)鍵、最基本的數(shù)據(jù)結(jié)構(gòu)。在Intel處理器中分為兩級:頁目錄、頁表,以下統(tǒng)稱為頁表。頁表是頁表項的數(shù)組,具有以下特征:1、頁表的內(nèi)容只能由內(nèi)核改變,進(jìn)程無法看到、更無法修改自己的頁表。2、頁表項具有非常豐富的含義。當(dāng)頁在內(nèi)存時,頁表項記錄映射關(guān)系和控制信息。當(dāng)頁不在內(nèi)存時,頁表項記錄頁面在外存中的位置。頁表項中包含有豐富的控制信息,可以實現(xiàn)對頁的管理和保護(hù)。4.3.1虛擬內(nèi)存抽象模型(頁表)3、頁表及其內(nèi)容可以動態(tài)變化。頁表項甚至頁表本身都可以動態(tài)地創(chuàng)建、修改、刪除、切換,以反映映射關(guān)系的變化。所有這些改變均由內(nèi)核完成,對用戶透明。4、頁表項的內(nèi)容不受限制。映射關(guān)系可動態(tài)變化。映射順序沒有要求,不需要連續(xù),也不需要有序??梢灾丿B,即可以將多個進(jìn)程的虛擬頁映射到同一個物理頁(共享)。5、通過頁表可以實現(xiàn)進(jìn)程虛擬地址空間的隔離。每個進(jìn)程都有自己的頁目錄和頁表,一個進(jìn)程不能使用別的進(jìn)程的頁表。進(jìn)程切換時,其頁目錄要同時切換。4.3.1虛擬內(nèi)存抽象模型(頁表)由于虛擬空間很大,所以頁表也很大。如4GB的虛擬地址空間有1024*1024個頁表項。采用一級頁表浪費空間,管理也不方便。所以,通常建立多級頁表。為了統(tǒng)一起見,Linux采用三級頁表。在Intel處理器中,第一級頁表對應(yīng)頁目錄,第二級頁表稱為頁中間表(目錄),第三級頁表對應(yīng)為處理器的頁表。每個頁目錄中有1024個頁目錄項,每個頁目錄項描述一個頁中間表;每個頁中間表只有1個頁中間項,每個頁中間項描述一個頁表;每個頁表有1024個頁表項,每個頁表項描述一個虛擬頁。4.3.1虛擬內(nèi)存抽象模型(頁表)頁目錄和頁表描述了進(jìn)程的整個虛擬地址空間。頁表項可以為空,頁目錄項也可以為空。如果頁目錄項為空,它對應(yīng)的整個頁表都不存在。事實上,進(jìn)程的頁表是在使用的過程中動態(tài)建立的。因此,進(jìn)程的頁表實際占用的空間要遠(yuǎn)遠(yuǎn)小于4MB。頁目錄和頁表是虛擬內(nèi)存管理的重要數(shù)據(jù)結(jié)構(gòu),虛擬內(nèi)存管理器通過不斷地調(diào)整頁目錄和頁表項來管理進(jìn)程的虛擬地址空間。4.3.1虛擬內(nèi)存抽象模型(VMA)進(jìn)程的所有信息,包括代碼、數(shù)據(jù)、堆棧、共享區(qū)等,都存放在它的虛擬地址空間中。由于屬性的不同,進(jìn)程對自己虛擬地址空間的使用方式也不同,因此對它們的管理方式也應(yīng)該不同。如程序代碼可以執(zhí)行但不能修改,數(shù)據(jù)部分可以讀寫但不能執(zhí)行,堆??梢詣討B(tài)地增長等。因此,應(yīng)該根據(jù)進(jìn)程的具體情況,將它的虛擬地址空間劃分成小的虛擬內(nèi)存區(qū)域(區(qū)間)。每個虛擬內(nèi)存區(qū)域就是一段具有相同屬性的、連續(xù)的虛擬地址空間。虛擬內(nèi)存區(qū)域可大可小,最小一頁,最大不超過4GB。4.3.1虛擬內(nèi)存抽象模型(VMA)structvm_area_struct{ structmm_struct *vm_mm; unsignedlong vm_start; unsignedlong vm_end; structvm_area_struct *vm_next; pgprot_t vm_page_prot; unsignedshort vm_flags; short vm_avl_height; //AVL樹 structvm_area_struct *vm_avl_left; structvm_area_struct *vm_avl_right; structvm_area_struct *vm_next_share;//用于映射頁和共享頁 structvm_area_struct **vm_pprev_share; structvm_operations_struct*vm_ops; unsignedlong vm_offset; structfile *vm_file; unsignedlong vm_pte; //共享內(nèi)存專用};4.3.1虛擬內(nèi)存抽象模型(VMA)structvm_operations_struct{ void(*open)(structvm_area_struct*area); void(*close)(structvm_area_struct*area); void(*unmap)(structvm_area_struct*area,unsignedlong,size_t); void(*protect)(structvm_area_struct*area,unsignedlong, size_t,unsignedintnewprot); int(*sync)(structvm_area_struct*area,unsignedlong, size_t,unsignedintflags); void(*advise)(structvm_area_struct*area,unsignedlong, size_t,unsignedintadvise); unsignedlong(*nopage)(structvm_area_struct*area, unsignedlongaddress,intwrite_access); unsignedlong(*wppage)(structvm_area_struct*area, unsignedlongaddress,unsignedlongpage); int(*swapout)(structvm_area_struct*,structpage*); pte_t(*swapin)(structvm_area_struct*,unsignedlong, unsignedlong);};4.3.1虛擬內(nèi)存抽象模型(VMA)vm_endvm_startvm_flagsvm_opsvm_offsetvm_filevm_nextvm_area_struct進(jìn)程的虛擬內(nèi)存opencloseunmapprotectsyncadvisenopagewppageswapoutswapin文件虛擬內(nèi)存區(qū)域用來彌補(bǔ)頁表項的不足。4.3.1虛擬內(nèi)存抽象模型(MM)一個進(jìn)程會有很多虛擬內(nèi)存區(qū)域,虛擬內(nèi)存管理器經(jīng)常需要使用這些虛擬內(nèi)存區(qū)域。如,當(dāng)發(fā)生缺頁異常時,要根據(jù)發(fā)生異常的虛擬地址,找到包含它的虛擬內(nèi)存區(qū)域,從而決定具體的處理方式。因此需要一種機(jī)制來管理一個進(jìn)程的所有vma結(jié)構(gòu)。另外,虛擬內(nèi)存管理器還需要一個結(jié)構(gòu)來記錄進(jìn)程中與內(nèi)存有關(guān)的信息。如進(jìn)程頁目錄的位置,進(jìn)程的代碼、數(shù)據(jù)、堆棧、堆、參數(shù)、環(huán)境變量等在虛擬空間中的位置,進(jìn)程駐留在物理內(nèi)存中的頁面?zhèn)€數(shù),進(jìn)程的LDT等。

為每個進(jìn)程建立一個內(nèi)存管理結(jié)構(gòu)mm_struct。4.3.1虛擬內(nèi)存抽象模型(MM)structmm_struct{ structvm_area_struct*mmap; //vma鏈表 structvm_area_struct*mmap_avl; //vma樹 structvm_area_struct*mmap_cache; //最后一次使用的vma pgd_t *pgd; //進(jìn)程的頁目錄 atomic_t count; //引用計數(shù) int map_count; //VMAs個數(shù) structsemaphore mmap_sem; unsignedlong context; unsignedlong start_code,end_code,start_data,end_data; unsignedlong start_brk,brk,start_stack; unsignedlong arg_start,arg_end,env_start,env_end; unsignedlong rss,total_vm,locked_vm; unsignedlong def_flags; unsignedlong cpu_vm_mask; unsignedlong swap_cnt; //可以換出的頁數(shù) unsignedlong swap_address; void *segments; //進(jìn)程的LDT};4.3.1虛擬內(nèi)存抽象模型(MM)

mmappgdvm_endvm_startvm_offsetvm_endvm_startvm_offsetvm_endvm_startvm_offsetmm_structvm_area_struct虛擬內(nèi)存區(qū)域1區(qū)域3區(qū)域2數(shù)據(jù)數(shù)據(jù)程序可執(zhí)行文件004.3.1虛擬內(nèi)存抽象模型訪問控制

每個vma中都包含有一個vm_page_prot域,其中記錄了缺省情況下對該區(qū)域的所有頁的保護(hù)權(quán)限設(shè)置。

真正對頁起到保護(hù)作用的是定義在各個頁表項中的訪問控制信息,對頁表項中訪問控制信息的設(shè)置要參考vma中的域vm_page_prot。

當(dāng)處理器轉(zhuǎn)換虛擬地址時,它利用頁表項中的控制信息檢查進(jìn)程對頁的訪問,防止進(jìn)程非法使用內(nèi)存。

限制對于內(nèi)存區(qū)域的訪問會提高系統(tǒng)的安全性。4.3.1虛擬內(nèi)存抽象模型按需調(diào)頁(DemandPaging)節(jié)省物理內(nèi)存的一種方法是只加載進(jìn)程當(dāng)前正在使用的虛擬頁。這種直到訪問時才加載虛擬頁的技術(shù)叫做按需調(diào)頁(demandpaging)。由于按需調(diào)頁,虛擬內(nèi)存管理器必須處理pagefault異常。使用按需調(diào)頁技術(shù)可以實現(xiàn)內(nèi)存映射,即將文件的內(nèi)容映射到進(jìn)程的虛擬內(nèi)存。4.3.1虛擬內(nèi)存抽象模型交換(Swapping)

物理內(nèi)存回收程序可能會回收進(jìn)程的頁,包括廢棄和換出。如果需要回收的頁來自磁盤上的映像或者數(shù)據(jù)文件,而且頁沒有被修改過,則可以直接將其廢棄。如果需要回收的頁已經(jīng)被修改過,則必須保留它的內(nèi)容以便恢復(fù)。保存到映像文件中保存到交換設(shè)備中虛擬內(nèi)存管理器必須仔細(xì)地處理頁的交換。有效的交換方案應(yīng)該保證所有進(jìn)程的工作集(workingset)都在物理內(nèi)存中。4.3.1虛擬內(nèi)存抽象模型高速緩存(Caches):1、BufferCache2、PageCache

3、SwapCache

4、HardwareCache:TLB(TranslationLookasideBuffers)4.3.1虛擬內(nèi)存抽象模型虛擬空間變化

1、在進(jìn)程創(chuàng)建時,從父進(jìn)程拷貝虛擬地址空間。

2、在進(jìn)程需要裝入新的執(zhí)行映像時,根據(jù)執(zhí)行映像的定義,重建它的內(nèi)存管理結(jié)構(gòu),從而重建進(jìn)程虛擬地址空間。3、缺頁異常處理程序會將頁讀入內(nèi)存,修改頁表。4、物理內(nèi)存回收程序會將暫時不用的頁從內(nèi)存中換出,修改頁表。5、在進(jìn)程結(jié)束時,釋放它在內(nèi)存中的所有頁和它的所有內(nèi)存管理結(jié)構(gòu),從而釋放它的虛擬地址空間。4.3.2虛擬內(nèi)存拷貝進(jìn)程創(chuàng)建時要拷貝父進(jìn)程的虛擬地址空間。好處是父子進(jìn)程可以完成同樣的工作(如Server),壞處是代價太高。解決的方法是:1、vfork:父進(jìn)程將自己的地址空間借給子進(jìn)程然后睡眠,直到子進(jìn)程重建自己的虛擬地址空間或exit退出。2、Copyonwrite:父子進(jìn)程有自己獨立的虛存管理結(jié)構(gòu)和頁目錄、頁表,且頁表項的內(nèi)容相同,但各頁都被設(shè)置為只讀。如果父或子進(jìn)程要修改某頁,系統(tǒng)會產(chǎn)生保護(hù)異常。異常處理程序識別出這種情況后,為修改頁面的進(jìn)程創(chuàng)建一個副本。如果沒有修改頁面的動作,父子進(jìn)程就會一直共享同一個頁面,不需要拷貝。

Linux同時支持上述兩種改進(jìn)。4.3.2虛擬內(nèi)存拷貝(一)inlineintcopy_mm(intnr,unsignedlongclone_flags,structtask_struct*tsk)

1、如果標(biāo)志clone_flags中設(shè)置了CLONE_VM,則將父進(jìn)程內(nèi)存結(jié)構(gòu)的引用記數(shù)加1,返回0。2、否則,要拷貝內(nèi)存結(jié)構(gòu):1)申請一個mm_struct結(jié)構(gòu)mm,將父進(jìn)程mm_struct結(jié)構(gòu)的內(nèi)容拷貝到mm:*mm=*current->mm;

2)調(diào)整mm的部分內(nèi)容,如mmap、引用計數(shù)等。3)為新進(jìn)程建立頁目錄:用戶部分(前0x300)清0,內(nèi)核部分(后0x100)從init_task的頁目錄中拷貝。4)將新頁目錄的地址寫入新進(jìn)程TSS段和mm->pgd中。5)將父進(jìn)程的所有虛擬內(nèi)存區(qū)域都拷貝到新進(jìn)程中來:dup_mmap(mm);4.3.2虛擬內(nèi)存拷貝(二)inlineintdup_mmap(structmm_struct*mm)1、順序搜索父進(jìn)程的vma鏈表,對其中的每個vma結(jié)構(gòu)mpnt做如下處理:1)從內(nèi)核內(nèi)存管理器申請一個vm_area_struct結(jié)構(gòu)tmp,并將mpnt的內(nèi)容拷貝到tmp中:*tmp=*mpnt;2)調(diào)整tmp的某些域,如vm_flags、vm_mm等。3)如果mpnt是一個文件映射區(qū)域,則將vm_file的引用計數(shù)加1,并將tmp加入文件inode結(jié)構(gòu)的vma鏈表中。4)copy_page_range(mm,current->mm,tmp);拷貝mpnt對應(yīng)的頁目錄、頁表項:5)如果tmp的操作集中定義有open操作,則執(zhí)行它。6)將tmp加入內(nèi)存管理結(jié)構(gòu)mm的vma隊列中。2、如果新進(jìn)程的內(nèi)存區(qū)域總數(shù)大于32,則為其建立AVL樹,以加快查找速度。4.3.2虛擬內(nèi)存拷貝(三)intcopy_page_range(structmm_struct*dst,structmm_struct*src,structvm_area_struct*vma)按照vma的開始和終止地址,找出它們在新、老頁目錄中的位置。順序拷貝各頁目錄項:1、拷貝目錄項:1)如果老目錄項為空,則不需要拷貝;2)如果老目錄項有錯,則將其清0;3)如果新目錄項為空,則創(chuàng)建一個新頁表。2、找到vma在新、老頁表中的位置,順序拷貝各頁表項:1)如果老頁表項為空,則不需要拷貝;2)如果老頁表項所指的頁不在內(nèi)存,則拷貝它,而后修改該頁在交換設(shè)備中的引用計數(shù);3)如果老頁表項為保留頁,則拷貝;4)如果老頁表項是copyonwrite頁,則將老頁表項改為只讀,拷貝;5)其余情況,清除老頁表項中的存取標(biāo)志,拷貝。4.3.3虛擬內(nèi)存重建當(dāng)進(jìn)程希望改變自己的行為時,它可以調(diào)用函數(shù)exec,根據(jù)新的執(zhí)行映像重建自己的虛擬地址空間(映像文件的裝入)。Linux采用內(nèi)存映射機(jī)制裝入執(zhí)行映像。實際是根據(jù)執(zhí)行映像文件建立一組vm_area_struct結(jié)構(gòu)。1、系統(tǒng)調(diào)用exec完成執(zhí)行映像的加載。2、系統(tǒng)調(diào)用old_mmap或sys_mmap可以為數(shù)據(jù)文件建立虛擬映射區(qū)域。函數(shù)do_mmap用于建立一個虛擬內(nèi)存區(qū)域。4.3.3虛擬內(nèi)存重建函數(shù)do_mmap建立的內(nèi)存映射區(qū)域有兩種:1、共享區(qū)域的頁允許多個進(jìn)程共享,它在內(nèi)存中只有一份拷貝,進(jìn)程可以直接修改共享映射區(qū)域的頁。當(dāng)需要將共享映射頁從內(nèi)存換出時,系統(tǒng)會將修改過的共享映射頁直接寫回到映射文件。2、私有區(qū)域的頁是進(jìn)程專有的,多個進(jìn)程可以同時讀它,但當(dāng)某進(jìn)程試圖寫時,系統(tǒng)會為寫進(jìn)程創(chuàng)建一個副本,進(jìn)程對私有映射頁的寫操作都在自己的副本上進(jìn)行。當(dāng)要將私有映射頁換出內(nèi)存時,系統(tǒng)會將其寫入交換設(shè)備,而不是映射文件。共享區(qū)域和私有區(qū)域的換出操作不同。4.3.3虛擬內(nèi)存重建unsignedlongdo_mmap(structfile*file,unsignedlongaddr,unsignedlonglen,unsignedlongprot,unsignedlongflags,unsignedlongoff)do_mmap完成如下工作:1、檢查各參數(shù)的合法性。2、找出映射區(qū)域的開始地址(可能不同于addr)。3、申請一個vm_area_struct結(jié)構(gòu),并根據(jù)參數(shù)填寫它。4、如果file不空,則執(zhí)行其上的mmap操作(設(shè)置操作集)。5、將vma插入mm_struct中,如果必要,建立vma的avl樹。

6、如果file不空,則將vma插入到文件inode的i_mmap隊列中。7、如果可能,合并兩個相臨的內(nèi)存區(qū)域。8、累計進(jìn)程虛擬內(nèi)存的總量,返回映射區(qū)域的開始地址。4.3.4缺頁處理當(dāng)CPU訪問到以下進(jìn)程頁時,會產(chǎn)生pagefault異常:1、不在內(nèi)存中的進(jìn)程頁;2、違反了保護(hù)約定的進(jìn)程頁。操作系統(tǒng)處理pagefault異常的一般過程是:1、找到發(fā)生異常的虛擬地址。2、根據(jù)虛擬地址查找包含它的虛擬內(nèi)存區(qū)域vma。如果找不到這樣的vma,或訪問方式確實違反了vma的保護(hù)約定,則向進(jìn)程發(fā)送SIGSEGV信號。3、找到異常頁對應(yīng)的頁表項。根據(jù)頁表項的內(nèi)容、虛擬內(nèi)存區(qū)域vma的內(nèi)容和異常錯誤代碼,決定如何處理異常。處理的方法包括:從映射文件上讀入頁,從交換設(shè)備上讀入頁,復(fù)制Copyonwrite頁,建立匿名頁等。4.3.4缺頁處理當(dāng)缺頁異常發(fā)生時,處理器在系統(tǒng)堆棧上壓入一個錯誤代碼(error_code)。錯誤代碼的意義如下:代碼位

意義

第0位P位0:引起異常的頁不在內(nèi)存1:引起異常的頁在內(nèi)存第1位W/R位0:引起異常的操作是讀1:引起異常的操作是寫第2位U/S位0:異常發(fā)生時,處理器在超級用戶模式1:異常發(fā)生時,處理器在普通用戶模式4.3.4缺頁處理缺頁處理函數(shù)是do_page_fault,定義如下:asmlinkagevoiddo_page_fault(structpt_regs*regs,unsignedlongerror_code)

它有兩個參數(shù):指向pt_regs結(jié)構(gòu)的指針和error_code。缺頁異常的處理過程如下:1、找到當(dāng)前進(jìn)程的內(nèi)存管理結(jié)構(gòu)mm。2、找到發(fā)生異常的地址address(CR2寄存器)。4.3.4缺頁處理3、檢查,看address是否在某vma中。找vm_end比address大的第一個vm_area_struct結(jié)構(gòu)vma。結(jié)果如下:1)找不到,轉(zhuǎn)bad_area。2)address在vma內(nèi),轉(zhuǎn)good_area。3)address在vma之下但vma不能或無法向下擴(kuò)展,轉(zhuǎn)bad_area。4)address在vma之下且vma能向下擴(kuò)展(用戶堆棧),則將其向下擴(kuò)展至少1頁。轉(zhuǎn)good_area。4.3.4缺頁處理4、good_area:根據(jù)異常錯誤碼決定處理方法:1)讀一個不存在的頁:如vma不允許讀或執(zhí)行,轉(zhuǎn)bad_area;否則,轉(zhuǎn)5。2)讀一個存在的頁:該頁肯定不可讀,因此出錯,轉(zhuǎn)bad_area。3)寫一個不存在的頁:如vma不允許寫,轉(zhuǎn)bad_area;否則,轉(zhuǎn)5。4)寫一個存在的頁:如vma不允許寫,轉(zhuǎn)bad_area;否則,說明要寫的是一個copyonwrite頁,轉(zhuǎn)5。5、正常缺頁處理handle_mm_fault()。如成功,則正常返回;否則,轉(zhuǎn)do_sigbus。4.3.4缺頁處理6、bad_area:1)如果異常發(fā)生時,處理器在用戶模式,則向當(dāng)前進(jìn)程發(fā)送一個SIGSEGV信號,告訴進(jìn)程出現(xiàn)段或頁違例,返回。通常情況下,該信號會導(dǎo)致進(jìn)程自殺。2)如果是CPU缺陷引起的異常,則修正它,返回。7、do_sigbus:1)給進(jìn)程發(fā)送一個SIGBUS信號;2)如果發(fā)生異常時,處理器在用戶態(tài),則返回;否則,轉(zhuǎn)no_context。8、no_context:1)內(nèi)核錯誤。如果能修復(fù)則修復(fù),返回。2)如果是對MMU寫保護(hù)功能的測試,則設(shè)置參數(shù),返回。3)壞頁且無法修復(fù)。顯示信息,終止整個系統(tǒng)的運行。4.3.4缺頁處理函數(shù)handle_mm_fault()的處理如下:1、找出address對應(yīng)的頁目錄項。如果頁目錄項有錯(保護(hù)標(biāo)志錯),則將其標(biāo)記為BAD_PAGETABLE,此次缺頁處理失敗,返回0。2、找出address對應(yīng)的頁表項:1)如果頁表不存在(頁目錄項的值為0),則創(chuàng)建一個新的頁表。2)根據(jù)address的第12到21位找到頁表項。調(diào)用函數(shù)handle_pte_fault()處理單個頁表項(單個虛擬頁)的異常。如果成功,返回1;否則,返回0。4.3.4缺頁處理函數(shù)handle_pte_fault()的處理過程如下:分析頁表項的內(nèi)容,找出頁的位置。有如下情況:1、頁不在內(nèi)存(p位為0),則:1)如頁表項為0,說明頁在映射文件中。從映射文件中讀入它:如果vma上沒有操作集,或其操作集中沒有nopage操作,則vma是匿名區(qū)域(不對應(yīng)任何文件)。處理匿名頁:do_anonymous_page()。調(diào)用vma操作集中的nopage操作,從映射文件或關(guān)系內(nèi)存中讀入頁:filemap_nopage()、shm_nopage()。2)如頁表項不為0,說明它在交換設(shè)備上。從交換設(shè)備上讀入頁:do_swap_page()。4.3.4缺頁處理2、頁在內(nèi)存,則:1)如果發(fā)生異常的動作是寫,且vma允許寫而頁不允許寫,則該頁是一個copyonwrite頁。為該頁創(chuàng)建一個拷貝:

do_wp_page(tsk,vma,address,pte);2)如果發(fā)生異常的動作是寫,且vma和頁都允許寫,則將頁表項上臟頁位設(shè)置為1、填入頁表、刷新TLB。3)如果發(fā)生異常的動作是讀,則將頁表項上存取位置1,填入頁表,刷新TLB表。4.3.4缺頁處理歸結(jié)起來,對缺頁的處理過程如下:do_page_fault

handle_mm_fault handle_pte_faultdo_swap_page do_no_page do_wp_pagedo_anonymous_page

filemap_nopage shm_nopage 對缺頁處理的方法有五種: 處理匿名頁:do_anonymous_page

處理映射文件頁:filemap_nopage

處理共享內(nèi)存頁:shm_nopage 處理交換設(shè)備頁:do_swap_page 處理Copyonwrite頁:do_wp_page4.3.4缺頁處理intdo_anonymous_page(structtask_struct*tsk,structvm_area_struct*vma,pte_t*page_table,intwrite_access)1、匿名頁都映射到empty_zero_page,該頁不能寫:1)如果引起異常的動作是讀,則根據(jù)empty_zero_page的地址和vma的保護(hù)信息創(chuàng)建一個頁表項,清除其中的_PAGE_RW標(biāo)志,將該頁設(shè)置為copyonwrite頁。2)如果引起異常的動作是寫,則:向物理內(nèi)存管理器申請一個新頁并將其清0。用新頁的地址和vma的保護(hù)信息創(chuàng)建一個頁表項,并在其中設(shè)置上_PAGE_DIRTY和_PAGE_RW標(biāo)志。2、將創(chuàng)建好的頁表項填入頁表。

3、成功,返回1。4.3.4缺頁處理unsignedlongfilemap_nopage(structvm_area_struct*area, unsignedlongaddress,intno_share)1、根據(jù)area找到文件,根據(jù)address算出頁在文件中的偏移量offset。2、根據(jù)文件的inode和offset查找頁緩存:1)頁不在緩存中:申請物理頁,將其加入頁緩存,調(diào)用inode上的readpage操作讀入該頁的內(nèi)容。此處可能一次讀入多頁。2)頁在緩存但正被鎖定(正在做I/O):等待。3)頁在緩存中但不是最新的:調(diào)用inode上的readpage操作讀入該頁。4)頁在緩存中且是最新的:如果area是共享的,則可以直接使用它。返回頁的開始地址。如果area是私有的,但引起異常的動作是讀,則可以直接使用它(設(shè)為寫保護(hù))。返回該頁的開始地址。如果area是私有的,且引起異常的動作是寫,則創(chuàng)建頁的一個副本。返回副本的開始地址。

5)如果上述任何一處出錯,則返回0,表示失敗。4.3.4缺頁處理共享內(nèi)存是進(jìn)程間的一種通信機(jī)制,它允許多個進(jìn)程通過共享內(nèi)存頁互相通信。由于一塊共享內(nèi)存對應(yīng)的物理頁可以出現(xiàn)在多個進(jìn)程的頁表中,因此對共享內(nèi)存缺頁的處理有些特別的地方。因為處理共享內(nèi)存的缺頁需要了解共享內(nèi)存機(jī)制,因此,將把對函數(shù)shm_nopage的討論推遲到第六章。4.3.4缺頁處理intdo_swap_page(structtask_struct*tsk,structvm_area_struct*vma, unsignedlongaddress,pte_t*page_table,pte_tentry,intwrite_access)1、如果vma中沒有定義swapin操作,則調(diào)用缺省的換入函數(shù): swap_in(tsk,vma,page_table,pte_val(entry),write_access);目前的所有虛擬內(nèi)存區(qū)域中都沒有定義換入函數(shù)。swap_in的定義在交換一節(jié)中討論。2、返回1,表示成功。4.3.4缺頁處理intdo_wp_page(structtask_struct*tsk,structvm_area_struct*vma, unsignedlongaddress,pte_t*page_table)1、如果頁本來就不在內(nèi)存或已經(jīng)允許寫,則返回1。2、如果老物理頁不存在,則向進(jìn)程發(fā)送SIGKILL信號,錯誤返回0。3、下列情況不需要拷貝物理頁:1)如果老物理頁的唯一一個用戶是當(dāng)前進(jìn)程;2)如果老物理頁只有兩個用戶(當(dāng)前進(jìn)程和交換緩存),而且沒有別的進(jìn)程引用該交換頁,則將其從交換緩存中刪除。 將頁置成可寫、臟頁,刷新頁表,返回1。4、如果頁有多個用戶,則需要拷貝:1)申請一個物理頁,將老頁的內(nèi)容拷貝到新頁中。2)根據(jù)新頁的物理地址和vma的保護(hù)權(quán)限構(gòu)造一個頁表項,在其中增加可寫、臟頁標(biāo)志,將其填入頁表中。3)釋放對老頁的引用,刷新TLB表,成功返回1。4.3.7頁緩存從文件中讀入頁需要經(jīng)過頁緩存。使用頁緩存(pagecache)的目的是:減少讀文件的次數(shù),加快對文件的訪問速度。從文件系統(tǒng)中讀入的每一頁(缺頁時讀入的頁和用read操作讀入的頁)都被緩存在頁緩存中。頁緩存中的頁包括共享映射頁和私有映射頁的主本,私有映射頁的副本不在頁緩存中。頁緩存是一個Hash表。structpage*page_hash_table[4096];

以VFSinode和文件中的偏移量為索引,來確定一個文件頁在頁緩存中的位置。4.3.7頁緩存page_hash_tablepagepagepagepagepage……Page結(jié)構(gòu)中的next_hash和pprev_hash指針用于將物理頁加入頁緩存4.3.7頁緩存1、當(dāng)需要從文件中讀入頁時,系統(tǒng)首先根據(jù)文件的VFSinode和頁在文件中的偏移量查頁緩存。如果需要的頁在頁緩存中,而且其內(nèi)容是最新的,就可以立刻使用它,從而可以避免一次I/O操作。只有當(dāng)要讀入的頁不在頁緩存或雖在頁緩存但內(nèi)容不是最新的時,才需要將其從文件中讀入。新讀入的頁也被加入頁緩存。通常情況下,Linux會啟動超前讀,即一次將多個文件頁讀入到內(nèi)存,并加入到頁緩存。4.3.7頁緩存2、當(dāng)需要回收物理內(nèi)存時,回收程序會搜索頁緩存,找無進(jìn)程引用的頁(引用計數(shù)為1):如頁是干凈的,可以直接將其廢棄、回收。如頁是臟的,可以先將其寫回文件、再回收。共享映射頁的回收是一種典型的情況。vm_endvm_startvm_flagsvm_opsvm_offsetvm_filevm_nextvm_area_struct虛擬內(nèi)存文件4.3.5共享映射頁的回收共享映射區(qū)域中的頁是和映射文件直接對應(yīng)的,其內(nèi)容來源于文件,進(jìn)程可以直接修改共享映射頁。映射文件是共享映射頁的備份。當(dāng)需要回收共享映射頁時:如頁未修改過,可以直接將其收回;如頁被修改過(臟的),可以先將其寫回映射文件,而后再將其收回。在兩種情況下,共享映射頁會寫回映射文件:1、物理內(nèi)存回收程序在回收被修改過(臟頁)的共享映射頁時;2、內(nèi)核守護(hù)進(jìn)程kpiod活動時。4.3.5共享映射頁的回收滿足以下條件的共享映射頁需要在回收前寫出(淘汰):1、在進(jìn)程的虛擬地址空間中,即該頁必須出現(xiàn)在進(jìn)程的某個虛擬內(nèi)存區(qū)域vma中。2、在內(nèi)存,即它的頁表項的存在位為1。3、最近未被存取過,即它的頁表項中的A位為0。4、不是內(nèi)核保留頁。5、頁上沒有加鎖,即在該頁上沒有正在進(jìn)行的I/O操作。6、不在交換緩存中。7、是臟頁(不臟的頁可以直接廢棄,不需要寫出)。8、是共享映射頁。4.3.5共享映射頁的回收回收程序try_to_swap_out對共享映射頁做如下工作:1、找到頁表項和page結(jié)構(gòu)。如果頁表項的A位為1,則將其清0,將page中的PG_referenced置1。返回。2、將共享映射頁在進(jìn)程頁表中的頁表項清0。3、使共享映射頁在TLB中失效。4、vma->vm_mm->rss--; //駐留內(nèi)存的頁數(shù)5、調(diào)用文件操作集上的寫操作(vma->vm_file->f_op->write()),將page的內(nèi)容寫到文件的offset處。6、釋放物理頁:__free_page(page_map);4.3.5共享映射頁的回收共享映射頁同時出現(xiàn)在頁緩存和進(jìn)程頁表中,因此該物理頁的引用計數(shù)至少是2。函數(shù)__free_page()僅僅將它的引用計數(shù)減1,并不能真正釋放它,物理頁仍然在頁緩存中。共享映射頁頁表物理內(nèi)存頁緩存4.3.5共享映射頁的回收如果函數(shù)__free_page()執(zhí)行后,物理頁的引用計數(shù)大于1,說明還有別的進(jìn)程引用它,該頁不會被回收。如果物理頁的引用計數(shù)為1,則在下一次回收物理內(nèi)存時,函數(shù)shrink_mmap()會檢查它的PG_referenced標(biāo)志:如該標(biāo)志為1,則將其清0,返回;否則,將它從頁緩存中刪除,從而真正將其回收。如果在頁被真正回收之前,又有進(jìn)程(包括釋放該共享映射頁的進(jìn)程)訪問了該頁,則缺頁處理程序會直接從頁緩存中查到該頁,從而又會將其加入到進(jìn)程的頁表,其引用計數(shù)就又會大于1,這樣以來,物理內(nèi)存回收程序就不會真正將其回收。4.3.5共享映射頁的回收這就是Linux采用的二次機(jī)會淘汰算法,是一種“l(fā)azy”的處理方法。將共享頁從進(jìn)程的虛擬地址空間寫出,但不立刻將其從頁緩存中釋放,有下列好處:1、如果該頁很快又被訪問,可以避免一次讀盤操作,從而可以提高系統(tǒng)的性能,也可以減少因淘汰失誤而造成的影響。2、如果到下次回收物理內(nèi)存時,該頁仍沒有被訪問,則根據(jù)局部訪問原則,該頁很快被訪問的可能性就較小,因此可以放心地將其回收。4.3.6交換如果需要回收的頁是私有映射頁的副本,則不應(yīng)該將它直接寫回映射文件,只能將其寫到外存的某個地方暫存。如果要回收的頁不是內(nèi)存映射頁,則該頁在磁盤上根本就沒有對應(yīng)的文件,因此只能將其寫到外存的某個地方暫存。用于暫存換出頁面的文件叫交換文件,用于暫存換出頁面的設(shè)備叫交換設(shè)備。以下統(tǒng)稱為交換設(shè)備。4.3.6交換在安裝Linux系統(tǒng)時,一般都要求創(chuàng)建交換設(shè)備。交換設(shè)備可能是單獨的塊設(shè)備,也可能是磁盤設(shè)備的一個分區(qū),當(dāng)然也可以是獨立的文件。為了提高性能,系統(tǒng)中可以建立多個交換設(shè)備,而且可以將這些交換設(shè)備分布在不同的塊設(shè)備(如磁盤)上。交換設(shè)備上沒有建立文件系統(tǒng),但它的第0頁上寫有特殊的控制信息。如下:4.3.6交換第0頁是下面形式的結(jié)構(gòu):unionswap_header{ struct{ charreserved[PAGE_SIZE-10]; //位圖 charmagic[10]; //魔數(shù) }magic; //老版本 struct{ char boo

溫馨提示

  • 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論