c檔案記憶體對映後分塊 程式的記憶體布局(下)

2021-10-13 18:15:17 字數 1778 閱讀 6997

翻譯:robotcode俱樂部

在堆疊下面,我們有記憶體對映段。在這裡,核心直接將檔案的內容對映到記憶體。任何應用程式都可以通過linux mmap()系統呼叫請求這樣的對映。記憶體對映是執行檔案i/o的一種方便高效的方法,因此常用於載入動態庫。還可以建立不對應於任何檔案的匿名記憶體對映,用於程式資料。在linux中,如果您通過malloc()請求乙個大記憶體塊,c庫將建立這樣乙個匿名對映,而不是使用堆記憶體。'大記憶體'表示大於mmap_threshold位元組,預設大小為128kb,可通過mallopt()進行調整。

堆提供執行時記憶體分配,就像棧一樣,這意味著資料必須比執行分配的函式活得更久,這與棧不同。大多數語言都提供了堆管理。在c語言中,堆分配的介面是malloc()。(以後會討論為什麼有時malloc不是在堆上分配記憶體)

如果堆中有足夠的空間來滿足記憶體請求,那麼程式執行時可以在不涉及核心的情況下處理它。否則,通過brk()系統呼叫(實現)來擴大堆,為請求的塊騰出空間。

堆管理是複雜的,需要複雜的演算法來實現高效的記憶體使用。堆請求所需的時間可以有很大的不同。實時系統有專門的分配器來處理這個問題。堆也會變得支離破碎,如下所示:

最後,我們討論記憶體的最低段:bss、資料段和程式段(程式段有時也翻譯成文字段)。bss和資料段都為c中的靜態(全域性)變數儲存內容。區別在於bss儲存未初始化的靜態變數的內容,這些靜態變數的值在源**中沒有被初始化設定。bss記憶體區域是匿名的:它不對映任何檔案。如果定義了 static int cntactiveusers,那麼cntactiveusers的內容就存在於bss中。

另一方面,資料段儲存源**中初始化的靜態變數的內容。這個記憶體區域不是匿名的。它對映程式二進位制映像中包含源**中給定的初始靜態值的部分。因此,如果定義了 static int cntworkerbees = 10,則cntworkerbees的內容位於資料段中,內容為10。即使資料段對映乙個檔案,它也是乙個私有記憶體對映,這意味著對記憶體的更新不會反映在底層檔案中。必須是這樣,否則分配給全域性變數將改變磁碟上的二進位制映像。不可思議!

圖中的示例比較複雜,因為它使用指標。在這種情況下,指標gonzo的內容駐留在資料段中。但是,它所指向的實際字串不是。該字串位於程式段(文字段)中,該文字段是唯讀的,儲存所有**,也包括字串常量。文字段還對映記憶體中的二進位制檔案,但寫入該區域會導致程式出現段錯誤(因為是唯讀的)。下面的圖表顯示了這些記憶體分段和我們的示例變數:

可以使用nm和objdump命令檢查二進位制映象,以顯示符號、它們的位址、段等等。最後,上面描述的虛擬位址布局是linux中的「靈活」布局方式,這是幾年來的預設布局。它假設我們有乙個rlimit_stack的值。如果不是這樣,linux就會恢復到「經典」布局,如下所示:

c 實現記憶體對映檔案共享記憶體

記憶體對映檔案是利用虛擬記憶體把檔案對映到程序的位址空間中去,在此之後程序操作檔案,就像操作程序空間裡的位址一樣了,比如使用c語言的 memcpy等記憶體操作的函式。這種方法能夠很好的應用在需要頻繁處理乙個檔案或者是乙個大檔案的場合,這種方式處理io效率比普通io效率要高 00001.using s...

利用記憶體對映檔案擴充程式可用的記憶體

windows利用頁交換檔案來擴充應用程式實際可用的記憶體,而不僅限於實際的32兆或64兆物理記憶體。但是windows的頁交換檔案是所有程式共用的,所以我們的程式要想獲得更大的記憶體還是比較困難,比如600兆或者更多。難道就沒有辦法了嗎?windows提供的記憶體對映檔案為我們提供解決問題的途徑。...

記憶體對映檔案

記憶體對映檔案是利用虛擬記憶體把檔案對映到程序的位址空間中去,在此之後程序操作文 件,就像操作程序空間裡的位址一樣了,比如使用 memcpy 等記憶體操作的函式。這種方法能 夠很好的應用在需要頻繁處理乙個檔案或者是乙個大檔案的場合,這種方式處理 io效率比 普通 io效率要高。另外,unix 把它做...