內存存儲數據時有兩種不同思路:低位優先和高位優先。
字節序
舉例來說,數值0x2211使用兩個字節儲存:高位字節是0x22,低位字節是0x11。
- 大端字節序:高位字節在前,低位字節在後,這是人類讀寫數值的方法。
- 小端字節序:低位字節在前,高位字節在後,即以0x1122形式儲存。
計算機電路先處理低位字節,效率比較高,因為計算都是從低位開始的。所以,計算機的內部處理都是小端字節序。但是,人類還是習慣讀寫大端字節序。所以,除了計算機的內部處理,其他的場合幾乎都是大端字節序,比如網絡傳輸和文件儲存。不同cpu平臺上字節序通常也不一樣,基於Intel技術的處理器是使用低位優先,基於摩托羅拉技術的處理器則使用高位優先。
int i_num = 0x12345678; printf("[0]:0x%x\n", *((char *)&i_num + 0)); printf("[1]:0x%x\n", *((char *)&i_num + 1)); printf("[2]:0x%x\n", *((char *)&i_num + 2)); printf("[3]:0x%x\n", *((char *)&i_num + 3)); #在不同平臺運行結果 [0]:0x78 [1]:0x56 [2]:0x34 [3]:0x12 [0]:0x12 [1]:0x34 [2]:0x56 [3]:0x78
參考了 https://www.cnblogs.com/gremount/p/8830707.html 的博主的文章
內存分段
我們不希望一個進程可以覆蓋另一個進程的數據,因此,內存被劃分成很多個小段,根據需要分配進程。
我們不希望當程序中動態數組不斷增長,超過了原來分配的空間,那麼就必須把整個程序拷貝到另一個更大的空間這種狀況發生,所以僅僅是把動態函數的那段移動到更大的空間,這樣效率會有很大的提高。簡單的說就是對於不同的程序塊,留不同的空閒空間,分開訪問。
硬件實現
段寄存器與其他寄存器一起合併生成內存地址。在眾多微處理器中有的有四個段寄存器,有的有六個段寄存器。段寄存器在實模式和保護模式的功能不一。
CS(代碼) 代碼段是保存微處理器執行代碼的內存段。代碼段寄存器持有段的起始位置。在實模式它定義64K內存段的起始位置。在保護模式它選擇它選擇一個描述符來描述段得起始位置和長度。在8088-80286上代碼段的限制是64K,在80386以上的保護模式中它的大小是4G。
DS(數據) 數據段是一個內存段包括大多數的程序中使用的數據。數據段中的數據被通過偏移地址或者持有偏移地址的其他寄存器的內容訪問。像代碼段一樣,它的大小在8088-80286上代碼段的限制是64K,在80386以上的保護模式中是4G。
ES(附加) 附加段是一個用來保存一些字符串指令的目標數據的附加數據段。
SS(堆棧) 堆棧段定義了堆棧使用的內存區域。堆棧的入口地址由堆棧段和堆棧指針寄存器決定,BP寄存器也可以在堆棧寄存器裡尋址。
FS和GS 這兩個段是80386-Pentium4 微處理器中提供的段來程序得到兩個附加段。Windows 用它完成一些內部操作,對它們沒有明確的定義。
虛擬內存轉換為物理地址
CPU將一個虛擬內存空間中的地址轉換為物理地址,需要進行兩步:首先將給定一個邏輯地址,CPU要利用其段式內存管理單元,先將為個邏輯地址轉換成一個線程地址(虛擬地址),再利用其頁式內存管理單元,轉換為最終物理地址。
物理地址就是,機器內主存的地址,包括RAM和ROM 。
邏輯地址就是,程序運行在內存中,使用的地址。
線性地址(虛擬地址)就是,cpu支持的內存空間遠遠大於機器主存的大小,這些多出來的空間對於程序來說是可以用的,這個時候的所有地址都稱為虛擬地址。
整個過程:邏輯地址(段表)->線性地址(頁表)->物理地址。
虛擬內存存在原因
- 實際上計算機所配置內存的實際空間常常小於處理器的尋址範圍,這是就會因處理器的一部分尋址空間沒有對應的物理存儲單元,從而導致處理器尋址能力的浪費。
- 還有一些處理器因外部地址線的根數小於處理器程序計數器的位數,而使地址總線的根數不滿足處理器的尋址範圍,從而處理器的其餘尋址能力也就被浪費了。例如:Intel8086處理器的程序計數器位32位,而處理器芯片的外部地址總線只有20根,所以它所能配置的最大內存為1MB:
- 在實際的應用中,如果需要運行的應用程序比較小,所需內存容量小於計算機實際所配置的內存空間,自然不會出什麼問題。但是,目前很多的應用程序都比較大,計算機實際所配置的內存空間無法滿足。一個應用程序總是逐段被運行的,而且在一段時間內會穩定運行在某一段程序裡。
這也就出現了一個方法:把要運行的那一段程序自輔存複製到內存中來運行,而其他暫時不運行的程序段就讓它仍然留在輔存。當需要執行另一端尚未在內存的程序段(如程序段2),如下圖所示,就可以把內存中程序段1的副本複製回輔存,在內存騰出必要的空間後,再把輔存中的程序段2複製到內存空間來執行即可: