【轉】linux內存管理---虛擬地址、邏輯地址、線性地址、物理地址的區別(一)

轉載:http://blog.csdn.net/yusiguyuan/article/details/9664887

分析linux內存管理機制,離不了上述幾個概念,在介紹上述幾個概念之前,先從《深入理解linux內核》這本書中摘抄幾段關于上述名詞的解釋:
一、《深入理解linux內核》的解釋
邏輯地址(Logical Address)
包含在機器語言指令中用來指定一個操作數或一條指令的地址(有點深奧)。這種尋址方式在80x86著名的分段結構中表現得尤為具體,它促使windows程序員把程序分成若干段。每個邏輯地址都由一個段和偏移量組成,偏移量指明了從段開始的地方到實際地址之間的距離。
線性地址(linear address)(也稱虛擬地址 virtual address)
是一個32位無符號整數,可以用來表示高達4GB的地址,線性地址通常用十六進制數字表示,值的范圍從0x00000000到0xffffffff。
物理地址(physical address)
用于內存芯片級內存單元尋址。它們與從微處理器的地址引腳按發送到內存總線上的電信號相對應。物理地址由32位或36位無符號整數表示。(其實這個最好理解,就是實實在在的地址)
(PS:在下面的解釋就可以看到,有時也將邏輯地址看做虛擬地址,但是《深入理解linux內核》中將線性地址看做虛擬地址)
首先說一句話:linux關于內存尋址可以分為幾個階段,首先由分段機制,然后有分頁機制。
分頁機制在段機制之后進行,以完成線性—物理地址的轉換過程。段機制把邏輯地址轉換為線性址頁機制進一步把該線性地址再轉換為物理地址 下面是我從網上查找資料了解到的,同時添加了自己的理解二、第二種解釋
邏輯地址(Logical Address)
是指由程序產生的與段相關的偏移地址部分。例如,你在進行C語言指針編程中,可以讀取指針變量本身值(&操作),實際上這個值就是邏輯地址,它是相對于你當前進程數據段的地址,不和絕對物理地址相干。只有在Intel實模式下,邏輯地址才和物理地址相等(因為實模式沒有分段或分頁機制,Cpu不進行自動地址轉換);邏輯也就是在Intel保護模式下程序執行代碼段限長內的偏移地址(假定代碼段、數據段如果完全一樣)。應用程序員僅需與邏輯地址打交道,而分段和分頁機制對您來說是完全透明的,僅由系統編程人員涉及。應用程序員雖然自己可以直接操作內存,那也只能在操作系統給你分配的內存段操作。(也就是說,咱們應用程序中看到的地址都是邏輯地址。) 如果是程序員,那么邏輯地址對你來說應該是輕而易舉就可以理解的。我們在寫C代碼的時候經常說我們定義的結構體首地址的偏移量,函數的入口偏移量,數組首地址等等。當我們在考究這些概念的時候,其實是相對于你這個程序而言的。并不是對于整個操作系統而言的。也就是說,邏輯地址是相對于你所編譯運行的具體的程序(或者叫進程吧,事實上在運行時就是當作一個進程來執行的)而言。你的編譯好的程序的入口地址可以看作是首地址,而邏輯地址我們通常可以認為是在這個程序中,編譯器為我們分配好的相對于這個首地址的偏移,或者說以這個首地址為起點的一個相對的地址值。(PS:這么來看,邏輯地址就是一個段內偏移量,但是這么說違背了邏輯地址的定義,在intel段是管理中,一個邏輯地址,是由一個段標識符加上一個指定段內相對地址的偏移量,表示為 [段標識符:段內偏移量]) 當我們雙擊一個可執行程序時,就是給操作系統提供了這個程序運行的入口地址。之后shell把可執行文件的地址傳入內核。進入內核后,會fork一個新的進程出來,新的進程首先分配相應的內存區域。這里會碰到一個著名的概念叫做Copy On Write,即寫時復制技術。這里不詳細講述,總之新的進程在fork出來之后,新的進程也就獲得了整個的PCB結構,繼而會調用exec函數轉而去將磁盤中的代碼加載到內存區域中。這時候,進程的PCB就被加入到可執行進程的隊列中,當CPU調度到這個進程的時候就真正的執行了。
我們大可以把程序運行的入口地址理解為邏輯地址的起始地址,也就是說,一個程序的開始的地址。以及以后用到的程序的相關數據或者代碼相對于這個起始地址的位置(這是由編譯器事先安排好的),就構成了我們所說的邏輯地址。邏輯地址就是相對于一個具體的程序(事實上是一個進程,即程序真正被運行時的相對地址)而言的。這么理解在細節上有一定的偏差,只要領會即可。 總之一句話,邏輯地址是相對于應用程序而言的。
邏輯地址產生的歷史背景: 追根求源,Intel的8位機8080CPU,數據總線(DB)為8位,地址總線(AB)為16位。那么這個16位地址信息也是要通過8位數據總線來傳送,也是要在數據通道中的暫存器,以及在CPU中的寄存器和內存中存放的,但由于AB正好是DB的整數倍,故不會產生矛盾!
但當上升到16位機后,Intel8086/8088CPU的設計由于當年IC集成技術和外封裝及引腳技術的限制,不能超過40個引腳。但又感覺到8位機原來的地址尋址能力216=64KB太少了,但直接增加到16的整數倍即令AB=32位又是達不到的。故而只能把AB暫時增加4條成為20條。則220=1MB的尋址能力已經增加了16倍。但此舉卻造成了AB的20位和DB的16位之間的矛盾,20位地址信息既無法在DB上傳送,又無法在16位的CPU寄存器和內存單元中存放。于是應運而生就產生了CPU段結構的原理。Intel為了兼容,將遠古時代的段式內存管理方式保留了下來,也就存在了邏輯地址
線性地址(Linear Address) 是邏輯地址到物理地址變換之間的中間層。程序代碼會產生邏輯地址,或者說是段中的偏移地址,加上相應段的基地址就生成了一個線性地址。如果啟用了分頁機制,那么線性地址可以再經變換以產生一個物理地址。若沒有啟用分頁機制,那么線性地址直接就是物理地址。Intel80386的線性地址空間容量為4G(2的32次方即32根地址總線尋址)。
我們知道每臺計算機有一個CPU(我們從單CPU來說吧。多CPU的情況應該是雷同的),最終所有的指令操作或者數據等等的運算都得由這個CPU來進行,而與CPU相關的寄存器就是暫存一些相關信息的存儲記憶設備。因此,從CPU的角度出發的話,我們可以將計算機的相關設備或者部件簡單分為兩類:一是數據或指令存儲記憶設備(如寄存器,內存等等),一種是數據或指令通路(如地址線,數據線等等)。線性地址的本質就是“CPU所看到的地址”。如果我們追根溯源,就會發現線性地址的就是伴隨著Intel的X86體系結構的發展而產生的。當32位CPU出現的時候,它的可尋址范圍達到4GB,而相對于內存大小來說,這是一個相當巨大的數字,我們也一般不會用到這么大的內存。那么這個時候CPU可見的4GB空間和內存的實際容量產生了差距。而線性地址就是用于描述CPU可見的這4GB空間。我們知道在多進程操作系統中,每個進程擁有獨立的地址空間,擁有獨立的資源。但對于某一個特定的時刻,只有一個進程運行于CPU之上。此時,CPU看到的就是這個進程所占用的4GB空間,就是這個線性地址。而CPU所做的操作,也是針對這個線性空間而言的。之所以叫線性空間,大概是因為人們覺得這樣一個連續的空間排列成一線更加容易理解吧。其實就是CPU的可尋址范圍。 對linux而言,CPU將4GB劃分為兩個部分,0-3GB為用戶空間(也可以叫核外空間),3-4GB為內核空間(也可以叫核內空間)。操作系統相關的代碼,即內核部分的代碼數據都會映射到內核空間,而用戶進程則會映射到用戶空間。至于系統是如何將線性地址轉換到實際的物理內存上,在下一篇文章講解,無外乎段式管理和頁式管理。
物理地址(Physical Address)是指出現在CPU外部地址總線上的尋址物理內存的地址信號,是地址變換的最終結果地址。如果啟用了分頁機制,那么線性地址會使用頁目錄和頁表中的項變換成物理地址。如果沒有啟用分頁機制,那么線性地址就直接成為物理地址了。
三、第三種解釋
虛擬內存(Virtual Memory) 是指計算機呈現出要比實際擁有的內存大得多的內存量。因此它允許程序員編制并運行比實際系統擁有的內存大得多的程序。這使得許多大型項目也能夠在具有有限內存資源的系統上實現。一個很恰當的比喻是:你不需要很長的軌道就可以讓一列火車從上海開到北京。你只需要足夠長的鐵軌(比如說3公里)就可以完成這個任務。采取的方法是把后面的鐵軌立刻鋪到火車的前面,只要你的操作足夠快并能滿足要求,列車就能象在一條完整的軌道上運行。這也就是虛擬內存管理需要完成的任務。在Linux0.11內核中,給每個程序(進程)都劃分了總容量為64MB的虛擬內存空間。因此程序的邏輯地址范圍是0x0000000到0x4000000。
有時我們也把邏輯地址稱為虛擬地址。因為與虛擬內存空間的概念類似,邏輯地址也是與實際物理內存容量無關的。(這一點和上面的解釋有一點區別,往下的解釋就按照這個繼續) 邏輯地址與物理地址的“差距”是0xC0000000,是由于虛擬地址->線性地址->物理地址映射正好差這個值。這個值是由操作系統指定的。
虛擬地址到物理地址的轉化方法是與體系結構相關的。一般來說有分段、分頁兩種方式。以現在的x86 cpu為例,分段分頁都是支持的。MemoryMangement Unit負責從邏輯地址到物理地址的轉化。邏輯地址是段標識+段內偏移量的形式,MMU通過查詢段表,可以把邏輯地址轉化為線性地址。如果cpu沒有開啟分頁功能,那么線性地址就是物理地址;如果cpu開啟了分頁功能,MMU還需要查詢頁表來將線性地址轉化為物理地址:邏輯地址 ----(段表)---> 線性地址 — (頁表)—> 物理地址不同的邏輯地址可以映射到同一個線性地址上;不同的線性地址也可以映射到同一個物理地址上;所以是多對一的關系。另外,同一個線性地址,在發生換頁以后,也可能被重新裝載到另外一個物理地址上。所以這種多對一的映射關系也會隨時間發生變化。
四、第四種解釋
程序(進程)的虛擬地址和邏輯地址

邏輯地址(logicaladdress)指程序產生的段內偏移地址。應用程序只與邏輯地址打交道,分段分頁對應用程序來說是透明的。也就是說C語言中的&,匯編語言中的符號地址,C中嵌入式匯編的”m”對應的都是邏輯地址。
邏輯地址是Intel為了兼容,將遠古時代的段式內存管理方式保留了下來。邏輯地址指的是機器語言指令中,用來指定一個操作數或者是一條指令的地址。以上例,我們說的連接器為A分配的0x08111111這個地址就是邏輯地址。不過不好意思,這樣說,好像又違背了Intel中段式管理中,對邏輯地址要求,“一個邏輯地址,是由一個段標識符加上一個指定段內相對地址的偏移量,表示為[段標識符:段內偏移量],也就是說,上例中那個0x08111111,應該表示為[A的代碼段標識符: 0x08111111],這樣,才完整一些”線性地址(linear address)或也叫虛擬地址(virtual address):跟邏輯地址類似,它也是一個不真實的地址,如果邏輯地址是對應的硬件平臺段式管理轉換前地址的話,那么線性地址則對應了硬件頁式內存的轉換前地址。
實際物理內存地址

物理地址(physicaladdress)是CPU外部地址總線上的尋址信號,是地址變換的最終結果,一個物理地址始終對應實際內存中的一個存儲單元。對80386保護模式來說,如果開啟分頁機制,線性地址經過頁變換產生物理地址。如果沒有開啟分頁機制,線性地址直接對應物理地址。頁目錄表項、頁表項對應都是物理地址。
是指出現在CPU外部地址總線上的尋址物理內存的地址信號,是地址變換的最終結果地址。如果啟用了分頁機制,那么線性地址會使用頁目錄和頁表中的項變換成物理地址。如果沒有啟用分頁機制,那么線性地址就直接成為物理地址了。
物理地址用于內存芯片級的單元尋址,與處理器和CPU連接的地址總線相對應。這個概念應該是這幾個概念中最好理解的一個,但是值得一提的是,雖然可以直接把物理地址理解成插在機器上那根內存本身,把內存看成一個從0字節一直到最大空量逐字節的編號的大數組,然后把這個數組叫做物理地址,但是事實上,這只是一個硬件提供給軟件的抽像,內存的尋址方式并不是這樣。所以,說它是“與地址總線相對應”,是更貼切一些,不過拋開對物理內存尋址方式的考慮,直接把物理地址與物理的內存一一對應,也是可以接受的。也許錯誤的理解更利于形而上的抽像。
Linux0.11的內核數據段,內核代碼段基地址都是0,所以對內核來說,邏輯地址就是線性地址。又因為1個頁目錄表和4個頁表完全映射16M物理內存,所以線性地址也就是物理地址。故對linux0.11內核來說,邏輯地址,線性地址,物理地址重合。


========================================================

   虛擬地址是對整個內存(不要與機器上插那條對上號)的抽像描述。它是相對于物理內存來講的,可以直接理解成“不真實的”,“假的”內存,例如,一個0x08000000內存地址,它并不對就物理地址上那個大數組中0x08000000 - 1那個地址元素;之所以是這樣,是因為現代操作系統都提供了一種內存管理的抽像,即虛擬內存(virtual memory)。進程使用虛擬內存中的地址,由操作系統協助相關硬件,把它“轉換”成真正的物理地址。這個“轉換”,是所有問題討論的關鍵。有了這樣的抽像,一個程序,就可以使用比真實物理地址大得多的地址空間。(拆東墻,補西墻,銀行也是這樣子做的),甚至多個進程可以使用相同的地址。不奇怪,因為轉換后的物理地址并非相同的??梢园堰B接后的程序反編譯看一下,發現連接器已經為程序分配了一個地址,例如,要調用某個函數A,代碼不是call A,而是call 0x0811111111 ,也就是說,函數A的地址已經被定下來了。沒有這樣的“轉換”,沒有虛擬地址的概念,這樣做是根本行不通的。打住了,這個問題再說下去,就收不住了。五、總結

CPU將一個虛擬內存空間中的地址轉換為物理地址,需要進行兩步:首先將給定一個邏輯地址(其實是段內偏移量,這個一定要理解?。。。?,CPU要利用其段式內存管理單元,先將為個邏輯地址轉換成一個線程地址,再利用其頁式內存管理單元,轉換為最終物理地址。
線性地址:是CPU所能尋址的空間或者范圍。物理地址:是機器中實際的內存地址。換言之,是機器中的內存容量范圍。邏輯地址:是對程序而言的。一般以Seg:Offset來表示。(程序員自己看到的地址)因此,若要確實比較三者的話,應有以下關系:線性地址大于等于物理地址(PS:但二者的地址空間是一樣的),而邏輯地址大于線性地址。邏輯地址通過段表變換成線性地址,此時如果并未開啟分頁機制的情況下,邏輯地址直接轉換成CPU所能尋址的空間。若已開啟則通過頁表完成線性地址到物理地址的變換。因此,三者最準確的關系是:邏輯地址通過線性地址完成物理地址的映射,線性地址在三者之中完全是充當"橋"的作用。
不管哪種解釋,都差不多,只不過把虛擬地址歸屬于剩下三種的哪一個的問題

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容