A. 現代操作系統中,一般採用()和()兩種存儲管理方法。—交換和虛擬內存有何不同
現在操作系統中,一般採用比較歡和兩組二交換的輕松管理方式,你交換和虛擬內容存在不同,根據他的不同進行交換和模擬的需要。
B. 闡述操作系統是如何對cpu,內存和磁碟進行管理的
cpu:基於優先順序的調度演算法
內存:虛擬內存、段頁式管理
磁碟:磁碟調度演算法、文件系統
C. 常用文件存儲設備管理方法有哪些操作系統課後題
率主要是通過內存分配功能實現的,內存分配的基本任務是為每道程序( ) 。使每道程序能在不受干擾 的環境下運行,主要是通過( )功能實現的。 Ⅰ.分配內存;Ⅱ.內存保護;Ⅲ.地址映射;Ⅳ.對換;Ⅴ.內存擴充;Ⅵ.邏輯地址到物理地址的變換;Ⅶ.內 存到外存間交換;Ⅷ.允許用戶程序的地址空間大於內存空間。 正確答案: Ⅰ;Ⅱ 4 適合多道程序運行的存儲管理中,存儲
D. linux中使用了什麼內存管理方法,為什麼
「事實勝於雄辯」,我們用一個小例子(原形取自《User-Level Memory Management》)來展示上面所講的各種內存區的差別與位置。
進程的地址空間對應的描述結構是「內存描述符結構」,它表示進程的全部地址空間,——包含了和進程地址空間有關的全部信息,其中當然包含進程的內存區域。
進程內存的分配與回收
創建進程fork()、程序載入execve()、映射文件mmap()、動態內存分配malloc()/brk()等進程相關操作都需要分配內存給進程。不過這時進程申請和獲得的還不是實際內存,而是虛擬內存,准確的說是「內存區域」。進程對內存區域的分配最終都會歸結到do_mmap()函數上來(brk調用被單獨以系統調用實現,不用do_mmap()),
內核使用do_mmap()函數創建一個新的線性地址區間。但是說該函數創建了一個新VMA並不非常准確,因為如果創建的地址區間和一個已經存在的地址區間相鄰,並且它們具有相同的訪問許可權的話,那麼兩個區間將合並為一個。如果不能合並,那麼就確實需要創建一個新的VMA了。但無論哪種情況,do_mmap()函數都會將一個地址區間加入到進程的地址空間中--無論是擴展已存在的內存區域還是創建一個新的區域。
同樣,釋放一個內存區域應使用函數do_ummap(),它會銷毀對應的內存區域。
如何由虛變實!
從上面已經看到進程所能直接操作的地址都為虛擬地址。當進程需要內存時,從內核獲得的僅僅是虛擬的內存區域,而不是實際的物理地址,進程並沒有獲得物理內存(物理頁面——頁的概念請大家參考硬體基礎一章),獲得的僅僅是對一個新的線性地址區間的使用權。實際的物理內存只有當進程真的去訪問新獲取的虛擬地址時,才會由「請求頁機制」產生「缺頁」異常,從而進入分配實際頁面的常式。
該異常是虛擬內存機制賴以存在的基本保證——它會告訴內核去真正為進程分配物理頁,並建立對應的頁表,這之後虛擬地址才實實在在地映射到了系統的物理內存上。(當然,如果頁被換出到磁碟,也會產生缺頁異常,不過這時不用再建立頁表了)
這種請求頁機制把頁面的分配推遲到不能再推遲為止,並不急於把所有的事情都一次做完(這種思想有點像設計模式中的代理模式(proxy))。之所以能這么做是利用了內存訪問的「局部性原理」,請求頁帶來的好處是節約了空閑內存,提高了系統的吞吐率。要想更清楚地了解請求頁機制,可以看看《深入理解linux內核》一書。
這里我們需要說明在內存區域結構上的nopage操作。當訪問的進程虛擬內存並未真正分配頁面時,該操作便被調用來分配實際的物理頁,並為該頁建立頁表項。在最後的例子中我們會演示如何使用該方法。
系統物理內存管理
雖然應用程序操作的對象是映射到物理內存之上的虛擬內存,但是處理器直接操作的卻是物理內存。所以當應用程序訪問一個虛擬地址時,首先必須將虛擬地址轉化成物理地址,然後處理器才能解析地址訪問請求。地址的轉換工作需要通過查詢頁表才能完成,概括地講,地址轉換需要將虛擬地址分段,使每段虛地址都作為一個索引指向頁表,而頁表項則指向下一級別的頁表或者指向最終的物理頁面。
每個進程都有自己的頁表。進程描述符的pgd域指向的就是進程的頁全局目錄。下面我們借用《linux設備驅動程序》中的一幅圖大致看看進程地址空間到物理頁之間的轉換關系。
上面的過程說起來簡單,做起來難呀。因為在虛擬地址映射到頁之前必須先分配物理頁——也就是說必須先從內核中獲取空閑頁,並建立頁表。下面我們介紹一下內核管理物理內存的機制。
物理內存管理(頁管理)
Linux內核管理物理內存是通過分頁機制實現的,它將整個內存劃分成無數個4k(在i386體系結構中)大小的頁,從而分配和回收內存的基本單位便是內存頁了。利用分頁管理有助於靈活分配內存地址,因為分配時不必要求必須有大塊的連續內存[3],系統可以東一頁、西一頁的湊出所需要的內存供進程使用。雖然如此,但是實際上系統使用內存時還是傾向於分配連續的內存塊,因為分配連續內存時,頁表不需要更改,因此能降低TLB的刷新率(頻繁刷新會在很大程度上降低訪問速度)。
鑒於上述需求,內核分配物理頁面時為了盡量減少不連續情況,採用了「夥伴」關系來管理空閑頁面。夥伴關系分配演算法大家應該不陌生——幾乎所有操作系統方面的書都會提到,我們不去詳細說它了,如果不明白可以參看有關資料。這里只需要大家明白Linux中空閑頁面的組織和管理利用了夥伴關系,因此空閑頁面分配時也需要遵循夥伴關系,最小單位只能是2的冪倍頁面大小。內核中分配空閑頁面的基本函數是get_free_page/get_free_pages,它們或是分配單頁或是分配指定的頁面(2、4、8…512頁)。
注意:get_free_page是在內核中分配內存,不同於malloc在用戶空間中分配,malloc利用堆動態分配,實際上是調用brk()系統調用,該調用的作用是擴大或縮小進程堆空間(它會修改進程的brk域)。如果現有的內存區域不夠容納堆空間,則會以頁面大小的倍數為單位,擴張或收縮對應的內存區域,但brk值並非以頁面大小為倍數修改,而是按實際請求修改。因此Malloc在用戶空間分配內存可以以位元組為單位分配,但內核在內部仍然會是以頁為單位分配的。
另外,需要提及的是,物理頁在系統中由頁結構structpage描述,系統中所有的頁面都存儲在數組mem_map[]中,可以通過該數組找到系統中的每一頁(空閑或非空閑)。而其中的空閑頁面則可由上述提到的以夥伴關系組織的空閑頁鏈表(free_area[MAX_ORDER])來索引。
內核內存使用
Slab
所謂尺有所長,寸有所短。以頁為最小單位分配內存對於內核管理系統中的物理內存來說的確比較方便,但內核自身最常使用的內存卻往往是很小(遠遠小於一頁)的內存塊——比如存放文件描述符、進程描述符、虛擬內存區域描述符等行為所需的內存都不足一頁。這些用來存放描述符的內存相比頁面而言,就好比是麵包屑與麵包。一個整頁中可以聚集多個這些小塊內存;而且這些小塊內存塊也和麵包屑一樣頻繁地生成/銷毀。
為了滿足內核對這種小內存塊的需要,Linux系統採用了一種被稱為slab分配器的技術。Slab分配器的實現相當復雜,但原理不難,其核心思想就是「存儲池[4]」的運用。內存片段(小塊內存)被看作對象,當被使用完後,並不直接釋放而是被緩存到「存儲池」里,留做下次使用,這無疑避免了頻繁創建與銷毀對象所帶來的額外負載。
Slab技術不但避免了內存內部分片(下文將解釋)帶來的不便(引入Slab分配器的主要目的是為了減少對夥伴系統分配演算法的調用次數——頻繁分配和回收必然會導致內存碎片——難以找到大塊連續的可用內存),而且可以很好地利用硬體緩存提高訪問速度。
Slab並非是脫離夥伴關系而獨立存在的一種內存分配方式,slab仍然是建立在頁面基礎之上,換句話說,Slab將頁面(來自於夥伴關系管理的空閑頁面鏈表)撕碎成眾多小內存塊以供分配,slab中的對象分配和銷毀使用kmem_cache_alloc與kmem_cache_free。
Kmalloc
Slab分配器不僅僅只用來存放內核專用的結構體,它還被用來處理內核對小塊內存的請求。當然鑒於Slab分配器的特點,一般來說內核程序中對小於一頁的小塊內存的請求才通過Slab分配器提供的介面Kmalloc來完成(雖然它可分配32到131072位元組的內存)。從內核內存分配的角度來講,kmalloc可被看成是get_free_page(s)的一個有效補充,內存分配粒度更靈活了。
有興趣的話,可以到/proc/slabinfo中找到內核執行現場使用的各種slab信息統計,其中你會看到系統中所有slab的使用信息。從信息中可以看到系統中除了專用結構體使用的slab外,還存在大量為Kmalloc而准備的Slab(其中有些為dma准備的)。
內核非連續內存分配(Vmalloc)
夥伴關系也好、slab技術也好,從內存管理理論角度而言目的基本是一致的,它們都是為了防止「分片」,不過分片又分為外部分片和內部分片之說,所謂內部分片是說系統為了滿足一小段內存區(連續)的需要,不得不分配了一大區域連續內存給它,從而造成了空間浪費;外部分片是指系統雖有足夠的內存,但卻是分散的碎片,無法滿足對大塊「連續內存」的需求。無論何種分片都是系統有效利用內存的障礙。slab分配器使得一個頁面內包含的眾多小塊內存可獨立被分配使用,避免了內部分片,節約了空閑內存。夥伴關系把內存塊按大小分組管理,一定程度上減輕了外部分片的危害,因為頁框分配不在盲目,而是按照大小依次有序進行,不過夥伴關系只是減輕了外部分片,但並未徹底消除。你自己比劃一下多次分配頁面後,空閑內存的剩餘情況吧。
所以避免外部分片的最終思路還是落到了如何利用不連續的內存塊組合成「看起來很大的內存塊」——這里的情況很類似於用戶空間分配虛擬內存,內存邏輯上連續,其實映射到並不一定連續的物理內存上。Linux內核借用了這個技術,允許內核程序在內核地址空間中分配虛擬地址,同樣也利用頁表(內核頁表)將虛擬地址映射到分散的內存頁上。以此完美地解決了內核內存使用中的外部分片問題。內核提供vmalloc函數分配內核虛擬內存,該函數不同於kmalloc,它可以分配較Kmalloc大得多的內存空間(可遠大於128K,但必須是頁大小的倍數),但相比Kmalloc來說,Vmalloc需要對內核虛擬地址進行重映射,必須更新內核頁表,因此分配效率上要低一些(用空間換時間)
與用戶進程相似,內核也有一個名為init_mm的mm_strcut結構來描述內核地址空間,其中頁表項pdg=swapper_pg_dir包含了系統內核空間(3G-4G)的映射關系。因此vmalloc分配內核虛擬地址必須更新內核頁表,而kmalloc或get_free_page由於分配的連續內存,所以不需要更新內核頁表。
vmalloc分配的內核虛擬內存與kmalloc/get_free_page分配的內核虛擬內存位於不同的區間,不會重疊。因為內核虛擬空間被分區管理,各司其職。進程空間地址分布從0到3G(其實是到PAGE_OFFSET,在0x86中它等於0xC0000000),從3G到vmalloc_start這段地址是物理內存映射區域(該區域中包含了內核鏡像、物理頁面表mem_map等等)比如我使用的系統內存是64M(可以用free看到),那麼(3G——3G+64M)這片內存就應該映射到物理內存,而vmalloc_start位置應在3G+64M附近(說"附近"因為是在物理內存映射區與vmalloc_start期間還會存在一個8M大小的gap來防止躍界),vmalloc_end的位置接近4G(說"接近"是因為最後位置系統會保留一片128k大小的區域用於專用頁面映射,還有可能會有高端內存映射區,這些都是細節,這里我們不做糾纏)。
上圖是內存分布的模糊輪廓
由get_free_page或Kmalloc函數所分配的連續內存都陷於物理映射區域,所以它們返回的內核虛擬地址和實際物理地址僅僅是相差一個偏移量(PAGE_OFFSET),你可以很方便的將其轉化為物理內存地址,同時內核也提供了virt_to_phys()函數將內核虛擬空間中的物理映射區地址轉化為物理地址。要知道,物理內存映射區中的地址與內核頁表是有序對應的,系統中的每個物理頁面都可以找到它對應的內核虛擬地址(在物理內存映射區中的)。
而vmalloc分配的地址則限於vmalloc_start與vmalloc_end之間。每一塊vmalloc分配的內核虛擬內存都對應一個vm_struct結構體(可別和vm_area_struct搞混,那可是進程虛擬內存區域的結構),不同的內核虛擬地址被4k大小的空閑區間隔,以防止越界——見下圖)。與進程虛擬地址的特性一樣,這些虛擬地址與物理內存沒有簡單的位移關系,必須通過內核頁表才可轉換為物理地址或物理頁。它們有可能尚未被映射,在發生缺頁時才真正分配物理頁面。
這里給出一個小程序幫助大家認清上面幾種分配函數所對應的區域。
#include<linux/mole.h>
#include<linux/slab.h>
#include<linux/vmalloc.h>
unsignedchar*pagemem;
unsignedchar*kmallocmem;
unsignedchar*vmallocmem;
intinit_mole(void)
{
pagemem = get_free_page(0);
printk("<1>pagemem=%s",pagemem);
kmallocmem = kmalloc(100,0);
printk("<1>kmallocmem=%s",kmallocmem);
vmallocmem = vmalloc(1000000);
printk("<1>vmallocmem=%s",vmallocmem);
}
voidcleanup_mole(void)
{
free_page(pagemem);
kfree(kmallocmem);
vfree(vmallocmem);
}
實例
內存映射(mmap)是Linux操作系統的一個很大特色,它可以將系統內存映射到一個文件(設備)上,以便可以通過訪問文件內容來達到訪問內存的目的。這樣做的最大好處是提高了內存訪問速度,並且可以利用文件系統的介面編程(設備在Linux中作為特殊文件處理)訪問內存,降低了開發難度。許多設備驅動程序便是利用內存映射功能將用戶空間的一段地址關聯到設備內存上,無論何時,只要內存在分配的地址范圍內進行讀寫,實際上就是對設備內存的訪問。同時對設備文件的訪問也等同於對內存區域的訪問,也就是說,通過文件操作介面可以訪問內存。Linux中的X伺服器就是一個利用內存映射達到直接高速訪問視頻卡內存的例子。
熟悉文件操作的朋友一定會知道file_operations結構中有mmap方法,在用戶執行mmap系統調用時,便會調用該方法來通過文件訪問內存——不過在調用文件系統mmap方法前,內核還需要處理分配內存區域(vma_struct)、建立頁表等工作。對於具體映射細節不作介紹了,需要強調的是,建立頁表可以採用remap_page_range方法一次建立起所有映射區的頁表,或利用vma_struct的nopage方法在缺頁時現場一頁一頁的建立頁表。第一種方法相比第二種方法簡單方便、速度快,但是靈活性不高。一次調用所有頁表便定型了,不適用於那些需要現場建立頁表的場合——比如映射區需要擴展或下面我們例子中的情況。
我們這里的實例希望利用內存映射,將系統內核中的一部分虛擬內存映射到用戶空間,以供應用程序讀取——你可利用它進行內核空間到用戶空間的大規模信息傳輸。因此我們將試圖寫一個虛擬字元設備驅動程序,通過它將系統內核空間映射到用戶空間——將內核虛擬內存映射到用戶虛擬地址。從上一節已經看到Linux內核空間中包含兩種虛擬地址:一種是物理和邏輯都連續的物理內存映射虛擬地址;另一種是邏輯連續但非物理連續的vmalloc分配的內存虛擬地址。我們的例子程序將演示把vmalloc分配的內核虛擬地址映射到用戶地址空間的全過程。
程序里主要應解決兩個問題:
第一是如何將vmalloc分配的內核虛擬內存正確地轉化成物理地址?
因為內存映射先要獲得被映射的物理地址,然後才能將其映射到要求的用戶虛擬地址上。我們已經看到內核物理內存映射區域中的地址可以被內核函數virt_to_phys轉換成實際的物理內存地址,但對於vmalloc分配的內核虛擬地址無法直接轉化成物理地址,所以我們必須對這部分虛擬內存格外「照顧」——先將其轉化成內核物理內存映射區域中的地址,然後在用virt_to_phys變為物理地址。
轉化工作需要進行如下步驟:
找到vmalloc虛擬內存對應的頁表,並尋找到對應的頁表項。
獲取頁表項對應的頁面指針
通過頁面得到對應的內核物理內存映射區域地址。
如下圖所示:
第二是當訪問vmalloc分配區時,如果發現虛擬內存尚未被映射到物理頁,則需要處理「缺頁異常」。因此需要我們實現內存區域中的nopaga操作,以能返回被映射的物理頁面指針,在我們的實例中就是返回上面過程中的內核物理內存映射區域中的地址。由於vmalloc分配的虛擬地址與物理地址的對應關系並非分配時就可確定,必須在缺頁現場建立頁表,因此這里不能使用remap_page_range方法,只能用vma的nopage方法一頁一頁的建立。
程序組成
map_driver.c,它是以模塊形式載入的虛擬字元驅動程序。該驅動負責將一定長的內核虛擬地址(vmalloc分配的)映射到設備文件上。其中主要的函數有——vaddress_to_kaddress()負責對vmalloc分配的地址進行頁表解析,以找到對應的內核物理映射地址(kmalloc分配的地址);map_nopage()負責在進程訪問一個當前並不存在的VMA頁時,尋找該地址對應的物理頁,並返回該頁的指針。
test.c它利用上述驅動模塊對應的設備文件在用戶空間讀取讀取內核內存。結果可以看到內核虛擬地址的內容(ok!),被顯示在了屏幕上。
執行步驟
編譯map_driver.c為map_driver.o模塊,具體參數見Makefile
載入模塊:insmodmap_driver.o
生成對應的設備文件
1在/proc/devices下找到map_driver對應的設備命和設備號:grepmapdrv/proc/devices
2建立設備文件mknodmapfilec 254 0(在我的系統里設備號為254)
利用maptest讀取mapfile文件,將取自內核的信息列印到屏幕上。
E. 系統內存怎麼管理
一、 進程的虛擬地址空間每個進程都被賦予自己的虛擬地址空間,對於32位進程來說,這個地址空間為4G,因此進程中的地址可以為0X00000000至0XFFFFFFFF之間的任何一個值。其中4G空間中的低區的2G空間留給進程使用,而高區的2G空間則留給系統使用。在Windows2000下,分區情況為:1、 NULL指針分配的分區NULL指針分配的分區占據0x00000000至0x0000FFFF,該分區的設置是為了幫助程序員掌握NULL指針的分配情況。例如當malloc或new分配失敗時就返回NULL,該分區的地址是禁止進入的,訪問該分區內的地址將發生訪問違規現象,同時終止該進程的運行。2、 用戶方式分區該分區是進程私有的地址空間,對於應用程序來講,該分區是維護進程的大部分數據的地方,所有的.exe和dll模塊均載入在這個分區,每個進程可以將dll載入到不同的地址中。對於.exe而言,一般載入到0x00400000地址處。進程的棧和堆也是在該分區中開辟的。3、 禁止進入分區該分區是用戶方式分區上禁止進入的分區,位於0x7FFF0000至0x7FFFFFFF,訪問該分區的任何企圖均將導致訪問違規,該分區的存在是為了防止用戶從用戶區訪問內核區的代碼。如:BYTE buf[70000];DWORD numWritten;WriteProcessMemory(GetCurrentProces(), (PVOID)0x7FFEEE90, buf, sizeof(buf), &numWritten);將有可能成功地將數據寫入只能有內核方式代碼訪問的內存。4、 內核方式分區該分區是存放操作系統代碼的地方,用於線程調度、內存管理、文件系統支持、網路支持和所有設備驅動程序的代碼全部在這個分區載入駐留在該分區的一切均可被所有近進程共享。二、 虛擬內存的實現本質上虛擬內存就是要讓一個程序的代碼和數據再沒有全部載入內存的情況下運行程序。運行過程中,當執行到尚未載入的內存代碼,或者要訪問還沒有載入到內存的數據時,虛擬內存管理器動態的將這部分代碼或數據從硬碟載入到內存中。而且在通常情況下,虛擬內存管理器也會相應的將內存中某些代碼或者數據置換到硬碟中,為即將載入的代碼或數據騰出地方。Win32中用來輔助實現虛擬內存的硬碟文件稱為「調頁文件」,調頁文件用來存放被虛擬內存管理器置換處內存的數據,當這些數據再次被進程訪問時,虛擬內存管理器會先將它們從調頁文件中置換進內存,這樣進程可以正確訪問這些數據。程序代碼(包括exe和dll文件)不會被修改,所以他們所在的頁被置換處內存時,並不會被寫進調頁文件中,而是直接拋棄,當再次被需要時,虛擬內存管理器直接從存放他們的exe或dll文件中找到他們並調入內存。三、 虛擬內存的狀態近處虛擬地址空間中的頁有三種狀態:自由(free)、預留(reserved)和提交(committed)。1、自由自由表示此頁尚未分配出去,可以用來滿足新的內存分配請求。2、預留預留是指從虛擬地址空間中劃出一塊區域(頁的整數倍大小),劃出之後的區域中的頁不能用來滿足新的內存分配請求,只是用來供要求「預留」此段區域的代碼以後使用,預留狀態的區域並沒有分配物理存儲,只是增加了一個描述進程虛擬地址空姐使用狀態的數據結構,用來記錄這塊區域已倍預留。 3、提交提交內存時會從調頁文件中開辟空間,並修改VAD中的相應項。當然,此時並沒有立刻從物理內存中分配空間,只是從磁碟的調頁文件中開辟空間。當有代碼第一次訪問這段提交內存中的某些數據時,系統發現並沒有真正的物理內存,拋出缺頁異常,虛擬內存管理器處理該異常,此時才會真正的分配物理內存。四、 虛擬內存狀態的管理Win32虛擬內存管理器使用一個數據結構(Virtual Address Descriptor, VAD)來記錄和維護每個進程4G的虛擬地址空姐的使用及狀態,美國進程都有自己的VAD集合,這個集合被組織成一個自平衡二叉樹。只有預留或提交的內存塊才有VAD,自由的內存塊沒有VAD,因此不在VAD數據結構中的虛擬地址就是自由的。每塊VAD數據結構記錄了該塊的起始地址以及當前狀態。五、 訪問虛擬內存時的處理流程對某虛擬內存區域進行了預留並提交之後,就可以對該區域中的數據進行訪問了,一下為訪問虛擬內存時的處理流程。1、當被訪問數據已在物理內存時,虛擬內存管理器只需記那個該數據的虛擬地址映射為物理指針。2、當被訪問的數據不在物理內存時,檢測此數據是否在調頁文件中或者在exe或dll文件中,若存在則進入下一步,否則發生訪問違例錯誤,進程退出。3、判斷內存中是否有空閑頁,若存在空閑頁,則直接將調頁文件或exe或dll文件的數據載入到該空閑頁中。 虛擬內存管理器維護了一個稱為「頁幀資料庫page-frame database」的數據結構,該數據結構時操作系統全局的,當系統啟動時被初始化,用來跟蹤和記錄物理內存真能乾的每個頁的狀態。4、當內存中不存在空閑頁時,根據調頁演算法,首先選擇出某個頁作為換出頁。5、判斷此頁自上次調進後是否修改過,若沒有被修改過,則將需要訪問的數據調入此頁,若被修改過,則需要先將此頁的內容寫到調頁文件與此頁相對應的備份頁中,並隨即將此頁標記為空閑頁。六、 虛擬地址到物理地址的映射當訪問的數據已在物理內存中後,需要將虛擬地址轉換為物理地址,即「地址映射」,才能真正訪問此數據。 每個進程都維護一套自己的層次表結構來實現地址映射。第一層稱為「目錄表」,實際上是一個內存頁,以四個位元組為單元分成1024個項,每一項稱為「頁目錄項」。第二層稱為「頁表」,共有1024個頁表,頁目錄表中的每個目錄表項對應這一層中的某個頁表,每個頁表也佔一個內存也,同樣被分成1024項,表頁的每一項稱為「頁表項」,每個頁表項指向物理內存中的某一個頁幀。第三層稱為頁幀,是真正存數數據的地方。當進行地址映射的時候,對應於層次表中的三個部分,頁將32位的地址分成三個部分,最高的十位對應頁目錄下標,次高的十位對應頁表的下標,低位的12位對應位元組下標作為頁內定址。
F. linux內核物理內存管理有哪些常用演算法 lru slab
採用夥伴演算法分配內存時,每次至少分配一個頁面。但當請求分配的內存大小為幾十個位元組或幾百個位元組時應該如何處理?如何在一個頁面中分配小的內存區,小內存區的分配所產生的內碎片又如何解決?
Linux2.0採用的解決辦法是建立了13個空閑區鏈表,它們的大小從32位元組到132056位元組。從Linux2.2開始,MM的開發者採用了一種叫做slab的分配模式,該模式早在1994年就被開發出來,用於Sun Microsystem Solaris 2.4操作系統中。Slab的提出主要是基於以下考慮:
· 內核對內存區的分配取決於所存放數據的類型。例如,當給用戶態進程分配頁面時,內核調用get_free_page()函數,並用0填充這個頁面。 而給內核的數據結構分配頁面時,事情沒有這么簡單,例如,要對數據結構所在的內存進行初始化、在不用時要收回它們所佔用的內存。因此,Slab中引入了對象這個概念,所謂對象就是存放一組數據結構的內存區,其方法就是構造或析構函數,構造函數用於初始化數據結構所在的內存區,而析構函數收回相應的內存區。但為了便於理解,你也可以把對象直接看作內核的數據結構。為了避免重復初始化對象,Slab分配模式並不丟棄已分配的對象,而是釋放但把它們依然保留在內存中。當以後又要請求分配同一對象時,就可以從內存獲取而不用進行初始化,這是在Solaris 中引入Slab的基本思想。
實際上,Linux中對Slab分配模式有所改進,它對內存區的處理並不需要進行初始化或回收。出於效率的考慮,Linux並不調用對象的構造或析構函數,而是把指向這兩個函數的指針都置為空。Linux中引入Slab的主要目的是為了減少對夥伴演算法的調用次數。
· 實際上,內核經常反復使用某一內存區。例如,只要內核創建一個新的進程,就要為該進程相關的數據結構(task_struct、打開文件對象等)分配內存區。當進程結束時,收回這些內存區。因為進程的創建和撤銷非常頻繁,因此,Linux的早期版本把大量的時間花費在反復分配或回收這些內存區上。從Linux2.2開始,把那些頻繁使用的頁面保存在高速緩存中並重新使用。
· 可以根據對內存區的使用頻率來對它分類。對於預期頻繁使用的內存區,可以創建一組特定大小的專用緩沖區進行處理,以避免內碎片的產生。對於較少使用的內存區,可以創建一組通用緩沖區(如Linux2.0中所使用的2的冪次方)來處理,即使這種處理模式產生碎片,也對整個系統的性能影響不大。
· 硬體高速緩存的使用,又為盡量減少對夥伴演算法的調用提供了另一個理由,因為對夥伴演算法的每次調用都會「弄臟」硬體高速緩存,因此,這就增加了對內存的平均訪問次數。
Slab分配模式把對象分組放進緩沖區(盡管英文中使用了Cache這個詞,但實際上指的是內存中的區域,而不是指硬體高速緩存)。因為緩沖區的組織和管理與硬體高速緩存的命中率密切相關,因此,Slab緩沖區並非由各個對象直接構成,而是由一連串的「大塊(Slab)」構成,而每個大塊中則包含了若干個同種類型的對象,這些對象或已被分配,或空閑,如圖6.12所示。一般而言,對象分兩種,一種是大對象,一種是小對象。所謂小對象,是指在一個頁面中可以容納下好幾個對象的那種。例如,一個inode結構大約佔300多個位元組,因此,一個頁面中可以容納8個以上的inode結構,因此,inode結構就為小對象。Linux內核中把小於512位元組的對象叫做小對象。
G. 操作系統的內存分配一般有哪幾種方式,各有什麼優缺點
一、程序載入
在早期的計算機中,要運行一個程序,會把這些程序全都裝入內存,程序都是直接運行在內存上的,也就是說程序中訪問的內存地址都是實際的物理內存地址。當計算機同時運行多個程序時,必須保證這些程序用到的內存總量要小於計算機實際物理內存的大小。
這樣會造成的問題有:
(1):進程地址空間不隔離。由於程序都是直接訪問物理內存,所以惡意程序可以隨意修改別的進程的內存數據,以達到破壞的目的。有些非惡意的,但是有bug的程序也可能不小心修改了其它程序的內存數據,就會導致其它程序的運行出現異常。
(2):內存使用效率低。有大量的數據在裝入裝出,導致效率十分低下。
(3):程序運行的地址不確定。因為是隨機分配的,所以程序運行的地址是不確定的。
二、虛擬內存
為了解決上述問題,人們想到了一種變通的方法,就是增加一個中間層,利用一種間接的地址訪問方法訪問物理內存。按照這種方法,程序中訪問的內存地址不再是實際的物理內存地址,而是一個虛擬地址,然後由操作系統將這個虛擬地址映射到適當的物理內存地址上。這樣,只要操作系統處理好虛擬地址到物理內存地址的映射,就可以保證不同的程序最終訪問的內存地址位於不同的區域,彼此沒有重疊,就可以達到內存地址空間隔離的效果。人們之所以要創建一個虛擬地址空間,目的是為了解決進程地址空間隔離的問題。但程序要想執行,必須運行在真實的內存上,所以,必須在虛擬地址與物理地址間建立一種映射關系。這樣,通過映射機制,當程序訪問虛擬地址空間上的某個地址值時,就相當於訪問了物理地址空間中的另一個值。人們想到了一種分段(Sagmentation)的方法,它的思想是在虛擬地址空間和物理地址空間之間做一一映射。
這種分段的映射方法雖然解決了上述中的問題一和問題三,但並沒能解決問題二,即內存的使用效率問題。在分段的映射方法中,每次換入換出內存的都是整個程序,這樣會造成大量的磁碟訪問操作,導致效率低下。所以這種映射方法還是稍顯粗糙,粒度比較大。實際上,程序的運行有局部性特點,在某個時間段內,程序只是訪問程序的一小部分數據,也就是說,程序的大部分數據在一個時間段內都不會被用到。基於這種情況,人們想到了粒度更小的內存分割和映射方法,這種方法就是分頁(Paging)。
(三):分頁
分頁的基本方法是,將地址空間分成許多的頁。每頁的大小由CPU決定,然後由操作系統選擇頁的大小。目前Inter系列的CPU支持4KB或4MB的頁大小,而PC上目前都選擇使用4KB。按這種選擇,4GB虛擬地址空間共可以分成1048576個頁,512M的物理內存可以分為131072個頁。顯然虛擬空間的頁數要比物理空間的頁數多得多。分頁方法的核心思想就是當可執行文件執行到第x頁時,就為第x頁分配一個內存頁y,然後再將這個內存頁添加到進程虛擬地址空間的映射表中,這個映射表就相當於一個y=f(x)函數。應用程序通過這個映射表就可以訪問到x頁關聯的y頁了。
一 頁式管理
1 頁式管理的基本原理將各進程的虛擬空間劃分成若干個長度相等的頁(page),頁式管理把內存空間按頁的大小劃分成片或者頁面(page frame),然後把頁式虛擬地址與內存地址建立一一對應頁表,並用相應的硬體地址變換機構,來解決離散地址變換問題。頁式管理採用請求調頁或預調頁技術實現了內外存存儲器的統一管理。 它分為
1 靜態頁式管理。靜態分頁管理的第一步是為要求內存的作業或進程分配足夠的頁面。系統通過存儲頁面表、請求表以及頁表來完成內存的分配工作。靜態頁式管理解決了分區管理時的碎片問題。但是,由於靜態頁式管理要求進程或作業在執行前全部裝入內存,如果可用頁面數小於用戶要求時,該作業或進程只好等待。而且作業和進程的大小仍受內存可用頁面數的限制。
2 動態頁式管理。動態頁式管理是在靜態頁式管理的基礎上發展起來的。它分為請求頁式管理和預調入頁式管理。
優點: 沒有外碎片,每個內碎片不超過頁大小。一個程序不必連續存放。便於改變程序佔用空間的大小(主要指隨著程序運行而動態生成的數據增多,要求地址空間相應增長,通常由系統調用完成而不是操作系統自動完成)。
缺點:程序全部裝入內存。
要求有相應的硬體支持。例如地址變換機構,缺頁中斷的產生和選擇淘汰頁面等都要求有相應的硬體支持。這增加了機器成本。增加了系統開銷,例如缺頁中斷處理機,請求調頁的演算法如選擇不當,有可能產生抖動現象。 雖然消除了碎片,但每個作業或進程的最後一頁內總有一部分空間得不到利用果頁面較大,則這一部分的損失仍然較大。
二 段式管理的基本思想
把程序按內容或過程(函數)關系分成段,每段有自己的名字。一個用戶作業或進程所包含的段對應一個二維線形虛擬空間,也就是一個二維虛擬存儲器。段式管理程序以段為單位分配內存,然後通過地址影射機構把段式虛擬地址轉換為實際內存物理地址。
程序通過分段(segmentation)劃分為多個模塊,如代碼段、數據段、共享段。其優點是: 可以分別編寫和編譯。 可以針對不同類型的段採取不同的保護。 可以按段為單位來進行共享,包括通過動態鏈接進行代碼共享。
三 段頁式管理的實現原理
1 虛地址的構成
一個進程中所包含的具有獨立邏輯功能的程序或數據仍被劃分為段,並有各自的段號s。這反映相繼承了段式管理的特徵。其次,對於段s中的程序或數據,則按照一定的大小將其劃分為不同的頁。和頁式系統一樣,最後不足一頁的部分仍佔一頁。這反映了段頁式管理中的頁式特徵。從而,段頁式管理時的進程的虛擬地址空間中的虛擬地址由三部分組成:即段號s,頁號P和頁內相對地址d。虛擬空間的最小單位是頁而不是段,從而內存可用區也就被劃分成為著干個大小相等的頁面,且每段所擁有的程序和數據在內存中可以分開存放。分段的大小也不再受內存可用區的限制。
2 段表和頁表
為了實現段頁式管理,系統必須為每個作業或進程建立一張段表以管理內存分配與釋放、缺段處理、存儲保護相地址變換等。另外,由於一個段又被劃分成了若干頁,每個段又必須建立一張頁表以把段中的虛頁變換成內存中的實際頁面。顯然,與頁式管理時相同,頁表中也要有相應的實現缺頁中斷處理和頁面保護等功能的表項。另外,由於在段頁式管理中,頁表不再是屬於進程而是屬於某個段,因此,段表中應有專項指出該段所對應頁表的頁表始址和頁表長度。
3 動態地址變換過程
在一般使用段頁式存儲管理方式的計算機系統中,都在內存中辟出一塊固定的區域存放進程的段表和頁表。因此,在段頁式管理系統中,要對內存中指令或數據進行一次存取的話,至少需要訪問三次以上的內存:
第一次是由段表地址寄存器得段表始址後訪問段表,由此取出對應段的頁表在內存中的地址。
第二次則是訪問頁表得到所要訪問的物理地址。
第三次才能訪問真正需要訪問的物理單元。
顯然,這將使CPU的執行指令速度大大降低。為了提高地址轉換速度,設置快速聯想寄存器就顯得比段式管理或頁式管理時更加需要。在快速聯想寄存器中,存放當前最常用的段號s、頁號p和對應的內存頁面與其它控制用欄目。當要訪問內存空間某一單元時,可在通過段表、頁表進行內存地址查找的同時,根據快速聯想寄存器查找其段號和頁號。如果所要訪問的段或頁在快速聯想寄存器中,則系統不再訪問內存中的段表、頁表而直接把快速聯想寄存器中的值與頁內相對地址d拼接起來得到內存地址。
總之,因為段頁式管理是段式管理的頁式管理方案結合而成的,所以具有它們二者的優點。但反過來說,由於管理軟體的增加,復雜性和開銷也就隨之增加了。另外,需要的硬體以及佔用的內存也有所增加。更重要的是,如果不採用聯想寄存器的方式提高CPU的訪內速度,將會使得執行速度大大下降