1. 程式人生 > 其它 >linux指標記憶體地址與64位虛擬記憶體上限

linux指標記憶體地址與64位虛擬記憶體上限

  記憶體地址在0x7ff16473d000,相當於‭140,674,749,157,376‬(127T965GB(131013GB)處開始,47位最大是128TB,131072GB),如下,也就是在使用者空間(0~0x7FFF FFFF FFFF,128GB)快頂部(差59GB)的位置。

  因為48bit空間也要滿足“兩頭頂格”的習慣,整個可用地址範圍變成了0~0x7FFF FFFF FFFF和0x8000 0000 0000~0xFFFF FFFF FFFF兩個不連續的地址空間上的的幾個更加離散的小島。以首位區分或者理解為正負符號,Linux Kernel使用“1”作為系統地址空間,使用“0”作為使用者地址空間(小於47bit可分配給使用者空間)。

  雖然段從低到高分配,棧從高到低分配,本質上都是一樣的,就像陣列從頭分配還是從尾分配,儲存上都是從前往後,從效率角度思考的優化結論,所以指標操作都是++為主。

  上右圖共享記憶體段中還包含了動態連結庫。其二,有些地方寫著共享記憶體段是從下往上、有些是從上往下(如上右圖),但肯定有個基址(要分配兩個驗證下?),從實際角度來看,從上往下更合適,為什麼?因為棧空間通過核心最大程序數就能估計出來,堆大小估計不出來,避免堆申請越界,所以從上往下是更合適的。

  對於linux程式而言,有一個非常重要的可執行檔案格式ELF(Executable and Linkable Format),它是物件檔案、可執行檔案、庫檔案、core dump檔案的格式。位於使用者空間的底部,通常在啟動時就確定並且不變。其組成部分從下到上為:

對可執行檔案而言,主要有4部分:.text, .data, .rodata和.bss(未初始化的資料),readelf -S execname可以檢視每部分的相對位置。data+bss+heap的大小由RLIMIT_DATA控制最大值。棧大小由RLIMIT_STACK控制。

(1)使用者空間:0x0000_0000_0000_0000到0x0000_ffff_ffff_ffff,一共有256TB。一般只用128TB,所以只會到0x7fff ffff ffff。

(2)非規範區域

(3)核心空間:0xffff_0000_0000_0000到0xffff_ffff_ffff_ffff。一共有256TB。一般只用128TB。應用程式設計不可見。

  核心空間又做了如下細分:

  • vmalloc區域:0xffff_0000_0000_0000到0xffff_7bff_bfff_0000,大小為126974GB。
  • vmemmap區域:0xffff_7bff_c000_0000到0xffff_7fff_c000_0000,大小為4096GB。
  • PCI I/O區域:0xffff_7fff_ae00_0000到0xffff_7fff_be00_0000,大小為16MB。
  • Modules區域:0xffff_7fff_c000_0000到0xffff_8000_0000_0000,大小為64MB。
  • normal memory線性對映區:0xffff_8000_0000_0000到0xffff_ffff_ffff_ffff,大小為128TB。主要從這裡開始。

  所以更準確的64為記憶體劃分如下:

綠色是使用者區,黃色是核心態。

使用者區域各部分的操作

  ELF各個部分的操作通常如下:

  交換區也是由頁表管理的。

  從下可知,heap是從低到高增長,共享記憶體從高到低。

  

  0x7f開頭的都是共享記憶體塊或其中的某個變數。

  程式程式碼段、資料段對映到可執行檔案的物理實現如下:

  

  每個程式都有起始地址、各個端的offset,重定位之後就得到執行時的絕對地址了,通過readelf可以看出。如下:

  雖然大多數程序不會訪問同一虛擬記憶體,但是也是可以的,例如程序間通訊常用的共享記憶體技術。如下:

  

記憶體子系統如何確定malloc、mmap、shm、程式啟動地址記憶體的地址

  待續。。 

虛擬地址到實體地址的轉換

  待續

參考:https://zhuanlan.zhihu.com/p/81399122

LightDB Enterprise Postgres--金融級關係型資料庫,更快、更穩、更懂金融!