頁目錄和頁表
⑴ 80386的linux中頁目錄表和頁表要佔多大的內存空間請詳述。謝謝。
1. 頁目錄表共有1K個表項,每個表項為4個位元組,因此頁目錄大小為4K,存儲在一個4K位元組的頁面中。
2. 一個頁表也存儲在一個4K位元組的頁面中。包含1K個表項,每個表項為4個位元組,大小4K。
3. 如果一個進程真的要用到全部4G(32位機哈~~)的存儲空間,那所有的頁表所佔用的空間為:
一個頁表大小4K*1024個頁表=4M
這樣頁目錄表和頁表所佔用的空間為
4K+4M
相對於將 所有的頁表項存儲在一個表中(不分頁目錄表和頁表),該表最大將佔4M位元組連續的物理存儲空間還要多4K。
但是傳說這個概率為0,所以頁表不會佔用達到4M。這樣就節省了空間。
希望我沒有搞錯,不要誤導你了。
⑵ 應用程序進程的頁目錄和頁表一共佔用了幾個物理頁頁框號分別是多少
1. 頁目錄表共有1K個表項,每個表項為4個位元組,因此頁目錄大小為4K,存儲在一個4K位元組的頁面中。
2. 一個頁表也存儲在一個4K位元組的頁面中。包含1K個表項,每個表項為4個位元組,大小4K。
3. 如果一個進程真的要用到全部4G(32位機哈~~)的存儲空間,那所有的頁表所佔用的空間為:
一個頁表大小4K*1024個頁表=4M
這樣頁目錄表和頁表所佔用的空間為
4K+4M
相對於將 所有的頁表項存儲在一個表中(不分頁目錄表和頁表),該表最大將佔4M位元組連續的物理存儲空間還要多4K。
但是傳說這個概率為0,所以頁表不會佔用達到4M。這樣就節省了空間。
希望我沒有搞錯,不要誤導你了。
⑶ 什麼是頁表頁
表模板建立起來以後只有一張表頁,為了滿足編制報表對表頁的需要,必須根據事先估計的表頁數量增加表頁.如要求編制該年12個月的貨幣資金錶因此需要12張表頁.
⑷ 什麼是頁表項
以x86的機器為例,當允許paging的時候:
頁表分了兩級,32位地址被劃分為10,10,12
CR3寄存器裝了第一級頁表(也叫頁目錄)的物理地址,這個地址一定是對齊到一個頁框的邊界的。這個對應的頁框將裝著第一級頁目錄,也就是說,頁目錄用掉了4KB,其中含有1024個頁目錄項,每個項佔4Byte。這每個4byte就是你所要問的東西了。每個項有20位是下一級的一個頁表的位置(為什麼是20位呢?因為intel設計的頁表是對其到4KB的邊界的,於是只要20位地址,再左移12位就得到了這個地址)。而另外的12位用於存放一些控制位,常見的有present,user, dirty, accessed,r/w等,具體的查intel的開發者手冊,上面講的很詳細。頁表項和頁目錄項內容差不多,稍有區別。
為了定位一個虛擬地址(在x86里應該是分段後的地址,叫線性地址),先拆出前10位,配合CR3找到相應的頁目錄項,然後得到了對應頁表的地址,在沒有錯誤的情況下再把線性地址的中間10位拿出來找到相應的頁表項,然後就讀出了20位(還沒左移12位,頁框肯定是對齊到4KB的邊界的)的這個線性地址對應的頁框,再加上12位就得到了物理地址。
⑸ 請問個頁目錄與頁表的物理地址問題
內核自己一套頁目錄和頁表====================是整個內核只有一套頁目錄和頁表還是每個模塊都有呢?另外:內核中的模塊是不是相對於進程呢
⑹ 什麼是操作系統頁表項
以x86的機器為例,當來允許源paging的時候:
1、頁表分了兩級,32位地址被劃分為10,10,12
2、CR3寄存器裝了第一級頁表(也叫頁目錄)的物理地址,這個地址一定是對齊到一個頁框的邊界的。這個對應的頁框將裝著第一級頁目錄,也就是說,頁目錄用掉了4KB,其中含有1024個頁目錄項,每個項佔4Byte。每個項有20位是下一級的一個頁表的位置。而另外的12位用於存放一些控制位。
3、為了定位一個虛擬地址,先拆出前10位,配合CR3找到相應的頁目錄項,然後得到了對應頁表的地址,在沒有錯誤的情況下再把線性地址的中間10位拿出來找到相應的頁表項,然後就讀出了20位的這個線性地址對應的頁框,再加上12位就得到了物理地址。
⑺ linux內存管理為什麼要建立頁表目錄
[地址映射](圖:左中)
linux內核使用頁式內存管理,應用程序給出的內存地址是虛擬地址,它需要經過若干級頁表一級一級的變換,才變成真正的物理地址。
想一下,地址映射還是一件很恐怖的事情。當訪問一個由虛擬地址表示的內存空間時,需要先經過若干次的內存訪問,得到每一級頁表中用於轉換的頁表項(頁表是存放在內存裡面的),才能完成映射。也就是說,要實現一次內存訪問,實際上內存被訪問了N+1次(N=頁表級數),並且還需要做N次加法運算。
所以,地址映射必須要有硬體支持,mmu(內存管理單元)就是這個硬體。並且需要有cache來保存頁表,這個cache就是TLB(Translation lookaside buffer)。
盡管如此,地址映射還是有著不小的開銷。假設cache的訪存速度是內存的10倍,命中率是40%,頁表有三級,那麼平均一次虛擬地址訪問大概就消耗了兩次物理內存訪問的時間。
於是,一些嵌入式硬體上可能會放棄使用mmu,這樣的硬體能夠運行VxWorks(一個很高效的嵌入式實時操作系統)、linux(linux也有禁用mmu的編譯選項)、等系統。
但是使用mmu的優勢也是很大的,最主要的是出於安全性考慮。各個進程都是相互獨立的虛擬地址空間,互不幹擾。而放棄地址映射之後,所有程序將運行在同一個地址空間。於是,在沒有mmu的機器上,一個進程越界訪存,可能引起其他進程莫名其妙的錯誤,甚至導致內核崩潰。
在地址映射這個問題上,內核只提供頁表,實際的轉換是由硬體去完成的。那麼內核如何生成這些頁表呢?這就有兩方面的內容,虛擬地址空間的管理和物理內存的管理。(實際上只有用戶態的地址映射才需要管理,內核態的地址映射是寫死的。)
[虛擬地址管理](圖:左下)
每個進程對應一個task結構,它指向一個mm結構,這就是該進程的內存管理器。(對於線程來說,每個線程也都有一個task結構,但是它們都指向同一個mm,所以地址空間是共享的。)
mm->pgd指向容納頁表的內存,每個進程有自已的mm,每個mm有自己的頁表。於是,進程調度時,頁表被切換(一般會有一個CPU寄存器來保存頁表的地址,比如X86下的CR3,頁表切換就是改變該寄存器的值)。所以,各個進程的地址空間互不影響(因為頁表都不一樣了,當然無法訪問到別人的地址空間上。但是共享內存除外,這是故意讓不同的頁表能夠訪問到相同的物理地址上)。
用戶程序對內存的操作(分配、回收、映射、等)都是對mm的操作,具體來說是對mm上的vma(虛擬內存空間)的操作。這些vma代表著進程空間的各個區域,比如堆、棧、代碼區、數據區、各種映射區、等等。
用戶程序對內存的操作並不會直接影響到頁表,更不會直接影響到物理內存的分配。比如malloc成功,僅僅是改變了某個vma,頁表不會變,物理內存的分配也不會變。
假設用戶分配了內存,然後訪問這塊內存。由於頁表裡面並沒有記錄相關的映射,CPU產生一次缺頁異常。內核捕捉異常,檢查產生異常的地址是不是存在於一個合法的vma中。如果不是,則給進程一個"段錯誤",讓其崩潰;如果是,則分配一個物理頁,並為之建立映射。
[物理內存管理](圖:右上)
那麼物理內存是如何分配的呢?
首先,linux支持NUMA(非均質存儲結構),物理內存管理的第一個層次就是介質的管理。pg_data_t結構就描述了介質。一般而言,我們的內存管理介質只有內存,並且它是均勻的,所以可以簡單地認為系統中只有一個pg_data_t對象。
每一種介質下面有若干個zone。一般是三個,DMA、NORMAL和HIGH。
DMA:因為有些硬體系統的DMA匯流排比系統匯流排窄,所以只有一部分地址空間能夠用作DMA,這部分地址被管理在DMA區域(這屬於是高級貨了);
HIGH:高端內存。在32位系統中,地址空間是4G,其中內核規定3~4G的范圍是內核空間,0~3G是用戶空間(每個用戶進程都有這么大的虛擬空間)(圖:中下)。前面提到過內核的地址映射是寫死的,就是指這3~4G的對應的頁表是寫死的,它映射到了物理地址的0~1G上。(實際上沒有映射1G,只映射了896M。剩下的空間留下來映射大於1G的物理地址,而這一部分顯然不是寫死的)。所以,大於896M的物理地址是沒有寫死的頁表來對應的,內核不能直接訪問它們(必須要建立映射),稱它們為高端內存(當然,如果機器內存不足896M,就不存在高端內存。如果是64位機器,也不存在高端內存,因為地址空間很大很大,屬於內核的空間也不止1G了);
NORMAL:不屬於DMA或HIGH的內存就叫NORMAL。
在zone之上的zone_list代表了分配策略,即內存分配時的zone優先順序。一種內存分配往往不是只能在一個zone里進行分配的,比如分配一個頁給內核使用時,最優先是從NORMAL裡面分配,不行的話就分配DMA裡面的好了(HIGH就不行,因為還沒建立映射),這就是一種分配策略。
每個內存介質維護了一個mem_map,為介質中的每一個物理頁面建立了一個page結構與之對應,以便管理物理內存。
每個zone記錄著它在mem_map上的起始位置。並且通過free_area串連著這個zone上空閑的page。物理內存的分配就是從這里來的,從 free_area上把page摘下,就算是分配了。(內核的內存分配與用戶進程不同,用戶使用內存會被內核監督,使用不當就"段錯誤";而內核則無人監督,只能靠自覺,不是自己從free_area摘下的page就不要亂用。)
[建立地址映射]
內核需要物理內存時,很多情況是整頁分配的,這在上面的mem_map中摘一個page下來就好了。比如前面說到的內核捕捉缺頁異常,然後需要分配一個page以建立映射。
說到這里,會有一個疑問,內核在分配page、建立地址映射的過程中,使用的是虛擬地址還是物理地址呢?首先,內核代碼所訪問的地址都是虛擬地址,因為CPU指令接收的就是虛擬地址(地址映射對於CPU指令是透明的)。但是,建立地址映射時,內核在頁表裡面填寫的內容卻是物理地址,因為地址映射的目標就是要得到物理地址。
那麼,內核怎麼得到這個物理地址呢?其實,上面也提到了,mem_map中的page就是根據物理內存來建立的,每一個page就對應了一個物理頁。
於是我們可以說,虛擬地址的映射是靠這里page結構來完成的,是它們給出了最終的物理地址。然而,page結構顯然是通過虛擬地址來管理的(前面已經說過,CPU指令接收的就是虛擬地址)。那麼,page結構實現了別人的虛擬地址映射,誰又來實現page結構自己的虛擬地址映射呢?沒人能夠實現。
這就引出了前面提到的一個問題,內核空間的頁表項是寫死的。在內核初始化時,內核的地址空間就已經把地址映射寫死了。page結構顯然存在於內核空間,所以它的地址映射問題已經通過「寫死」解決了。
由於內核空間的頁表項是寫死的,又引出另一個問題,NORMAL(或DMA)區域的內存可能被同時映射到內核空間和用戶空間。被映射到內核空間是顯然的,因為這個映射已經寫死了。而這些頁面也可能被映射到用戶空間的,在前面提到的缺頁異常的場景裡面就有這樣的可能。映射到用戶空間的頁面應該優先從HIGH區域獲取,因為這些內存被內核訪問起來很不方便,拿給用戶空間再合適不過了。但是HIGH區域可能會耗盡,或者可能因為設備上物理內存不足導致系統裡面根本就沒有HIGH區域,所以,將NORMAL區域映射給用戶空間是必然存在的。
但是NORMAL區域的內存被同時映射到內核空間和用戶空間並沒有問題,因為如果某個頁面正在被內核使用,對應的page應該已經從free_area被摘下,於是缺頁異常處理代碼中不會再將該頁映射到用戶空間。反過來也一樣,被映射到用戶空間的page自然已經從free_area被摘下,內核不會再去使用這個頁面。
[內核空間管理](圖:右下)
除了對內存整頁的使用,有些時候,內核也需要像用戶程序使用malloc一樣,分配一塊任意大小的空間。這個功能是由slab系統來實現的。
slab相當於為內核中常用的一些結構體對象建立了對象池,比如對應task結構的池、對應mm結構的池、等等。
而slab也維護有通用的對象池,比如"32位元組大小"的對象池、"64位元組大小"的對象池、等等。內核中常用的kmalloc函數(類似於用戶態的malloc)就是在這些通用的對象池中實現分配的。
slab除了對象實際使用的內存空間外,還有其對應的控制結構。有兩種組織方式,如果對象較大,則控制結構使用專門的頁面來保存;如果對象較小,控制結構與對象空間使用相同的頁面。
除了slab,linux 2.6還引入了mempool(內存池)。其意圖是:某些對象我們不希望它會因為內存不足而分配失敗,於是我們預先分配若干個,放在mempool中存起來。正常情況下,分配對象時是不會去動mempool裡面的資源的,照常通過slab去分配。到系統內存緊缺,已經無法通過slab分配內存時,才會使用 mempool中的內容。
[頁面換入換出](圖:左上)(圖:右上)
頁面換入換出又是一個很復雜的系統。內存頁面被換出到磁碟,與磁碟文件被映射到內存,是很相似的兩個過程(內存頁被換出到磁碟的動機,就是今後還要從磁碟將其載回內存)。所以swap復用了文件子系統的一些機制。
頁面換入換出是一件很費CPU和IO的事情,但是由於內存昂貴這一歷史原因,我們只好拿磁碟來擴展內存。但是現在內存越來越便宜了,我們可以輕松安裝數G的內存,然後將swap系統關閉。於是swap的實現實在讓人難有探索的慾望,在這里就不贅述了。(另見:《linux內核頁面回收淺析》)
[用戶空間內存管理]
malloc是libc的庫函數,用戶程序一般通過它(或類似函數)來分配內存空間。
libc對內存的分配有兩種途徑,一是調整堆的大小,二是mmap一個新的虛擬內存區域(堆也是一個vma)。
在內核中,堆是一個一端固定、一端可伸縮的vma(圖:左中)。可伸縮的一端通過系統調用brk來調整。libc管理著堆的空間,用戶調用malloc分配內存時,libc盡量從現有的堆中去分配。如果堆空間不夠,則通過brk增大堆空間。
當用戶將已分配的空間free時,libc可能會通過brk減小堆空間。但是堆空間增大容易減小卻難,考慮這樣一種情況,用戶空間連續分配了10塊內存,前9塊已經free。這時,未free的第10塊哪怕只有1位元組大,libc也不能夠去減小堆的大小。因為堆只有一端可伸縮,並且中間不能掏空。而第10塊內存就死死地佔據著堆可伸縮的那一端,堆的大小沒法減小,相關資源也沒法歸還內核。
當用戶malloc一塊很大的內存時,libc會通過mmap系統調用映射一個新的vma。因為對於堆的大小調整和空間管理還是比較麻煩的,重新建一個vma會更方便(上面提到的free的問題也是原因之一)。
那麼為什麼不總是在malloc的時候去mmap一個新的vma呢?第一,對於小空間的分配與回收,被libc管理的堆空間已經能夠滿足需要,不必每次都去進行系統調用。並且vma是以page為單位的,最小就是分配一個頁;第二,太多的vma會降低系統性能。缺頁異常、vma的新建與銷毀、堆空間的大小調整、等等情況下,都需要對vma進行操作,需要在當前進程的所有vma中找到需要被操作的那個(或那些)vma。vma數目太多,必然導致性能下降。(在進程的vma較少時,內核採用鏈表來管理vma;vma較多時,改用紅黑樹來管理。)
[用戶的棧]
與堆一樣,棧也是一個vma(圖:左中),這個vma是一端固定、一端可伸(注意,不能縮)的。這個vma比較特殊,沒有類似brk的系統調用讓這個vma伸展,它是自動伸展的。
當用戶訪問的虛擬地址越過這個vma時,內核會在處理缺頁異常的時候將自動將這個vma增大。內核會檢查當時的棧寄存器(如:ESP),訪問的虛擬地址不能超過ESP加n(n為CPU壓棧指令一次性壓棧的最大位元組數)。也就是說,內核是以ESP為基準來檢查訪問是否越界。
但是,ESP的值是可以由用戶態程序自由讀寫的,用戶程序如果調整ESP,將棧劃得很大很大怎麼辦呢?內核中有一套關於進程限制的配置,其中就有棧大小的配置,棧只能這么大,再大就出錯。
對於一個進程來說,棧一般是可以被伸展得比較大(如:8MB)。然而對於線程呢?
首先線程的棧是怎麼回事?前面說過,線程的mm是共享其父進程的。雖然棧是mm中的一個vma,但是線程不能與其父進程共用這個vma(兩個運行實體顯然不用共用一個棧)。於是,在線程創建時,線程庫通過mmap新建了一個vma,以此作為線程的棧(大於一般為:2M)。
可見,線程的棧在某種意義上並不是真正棧,它是一個固定的區域,並且容量很有限。
附上出處鏈接:http://www.cnblogs.com/zhaoyl/p/3695517.html
⑻ 關於虛擬內存中頁目錄與頁表在物理內存中載入的問題
我對Linux操作系統的具體情況不是很熟,回答僅供參考。
首先,物理內存無所謂內核區用戶區,所有地址都一樣。虛擬的地址空間才分內核區用戶區。
處理器通過查看頁目錄和頁表,把虛擬地址換算成物理地址。用戶區與內核區的兩個不同的虛擬地址對應同一個物理地址也不要緊。
內核區與用戶區的真正區別在於普通進程能不能訪問該區域中的地址。
在正常情況下,操作系統肯定會把頁目錄和頁表保護起來,可以把它們看作存放在內核區的東西。
編寫操作系統時,頁目錄確實可以放在物理內存中的任何地方(當然偏移必須是1000h的倍數),只要把偏移量填進CR3的高20位就可以了。
Linux內核的頁目錄放在物理地址0h處,頁表緊隨其後。0.11版Linux中,所有用戶進程和內核用的都是這張頁目錄。切換進程時,改改頁目錄項就行了。新版的Linux內核我不太了解,抱歉……
每個頁目錄項有4位元組,高20位儲存頁表的物理地址,低12位儲存頁表的屬性。
一張頁表4KB,這4KB必須是連續的。但是各張頁表之間不必連續。Linux創建新進程時,僅僅調用了get_free_page找到一頁空內存,把進程頁表塞進去而已。
頁表不能被普通進程直接訪問。訪問用戶區虛擬地址是看不到進程頁表的。
內核的頁表前面提到過。它就在內核頁目錄的後面,物理地址為1000h,虛擬地址為C0001000h。訪問用戶區的虛擬地址不會看到它。
個人不大擅長表述,恐怕解釋得不是很清楚。歡迎追問。
⑼ 頁面大小和頁表項之間有必然的聯系么
一、理解這樣一個概念,操作系統為了方便管理內存,將內存劃分成很若干個頁,每個頁表項就代表一個頁的地址(頁的地址,不是內存地址)。
二、4B大小的頁表項,意味著支持最大的頁表數是2的32次方=4294967296 (4B=32bit),一個頁的大小4K,那麼4B大小的頁表項,表示操作系統支持4294967296*4K = 16GB大的內存。
三、現在問題是頁表佔用一定的內存。
(一)現在假設有2GB(一定要小於16GB)內存。
1、那麼它一共有2GB/4KB=512K個頁,也就是說頁表項有512K項,而每個頁表項的大小4B,那麼頁表在內存中佔用的大小是:512K*4B=2MB,意味著,只要2MB就可以表示512K個頁(每個頁是4KB,總內存大小是2G),它頁表本身佔用了2MB/4K=512個頁。
2、這一題 就是問你1個頁可以表示多少個頁表項,4KB/4B=1024個頁表項。頁面大小與頁表項沒有絕對的關系,但它們有這樣關系:
(二)頁面大小 * 2 ^(頁表項大小)=操作系統最大支持內存大小(虛擬內存)
1、本題是 4K * 2^(4B) = 16GB
2、頁表佔用內存 = 操作系統內存/頁面大小 * 頁表項大小,本題是,假設操作系統內存為2GB。 2GB/4KB*4B = 2MB
3、頁表佔用的頁數是=頁表佔用內存/頁面大小,這題同上假設2MB/4K=512個頁。
(9)頁目錄和頁表擴展閱讀
一、地址結構
1、邏輯地址:CPU所生成的地址。CPU產生的邏輯地址被分為 :p (頁號) 它包含每個頁在物理內存中的基址,用來作為頁表的索引;d (頁偏移),同基址相結合,用來確定送入內存設備的物理內存地址。
2、物理地址:內存單元所看到的地址。邏輯地址空間為2^m,且頁大小為2^n,那麼邏輯地址的高m-n位表示頁號,低n位表示頁偏移。
3、邏輯地址空間:由程序所生成的所有邏輯地址的集合。
4、物理地址空間:與邏輯地址相對應的內存中所有物理地址的集合,用戶程序看不見真正的物理地址。
5、註:用戶只生成邏輯地址,且認為進程的地址空間為0到max。物理地址范圍從R+0到R+max,R為基地址,地址映射-將程序地址空間中使用的邏輯地址變換成內存中的物理地址的過程。由內存管理單元(MMU)來完成。
6、分頁邏輯地址 =P(頁號).d(頁內位移)
7、分頁物理地址=f(頁幀號).d(同上)
8、P = 線性邏輯地址/頁面大小
9、d= 線性邏輯地址-P*頁面大小
二、基本分頁存儲管理方式
用固定大小的頁(Page)來描述邏輯地址空間,用相同大小的頁框(Frame)來描述物理內存空間,由操作系統實現從邏輯頁到物理頁框的頁面映射,同時負責對所有頁的管理和進程運行的控制。
三、分級頁表
1、一個32位邏輯地址空間的計算機系統,頁大小為4KB,那麼頁表有一百萬條目。假設每個條目佔4B,則需要4MB物理地址空間來存儲頁表本身。利用多級頁表,可以減少頁表所佔用的空間。
2、一個邏輯地址(32位系統,頁大小 4K) 可以被分為 :一個20位的頁號 +一個12位的偏移。如果對頁表進行再分頁,那麼頁號分解為:一個10位的頁號 +一個10位的偏移。因此,一個邏輯地址表示如下 :p1 是用來訪問外部頁表的索引, p2 是外部頁表的頁偏移。