簡體   English   中英

堆和堆棧內存是如何管理、實現和分配的?

[英]How is heap and stack memories managed, implemented, allocated?

在 C/C++ 中,我們可以將變量、函數、成員函數、類的實例存儲在堆棧或堆上。

每個是如何實現的? 它是如何管理的(高級)? gcc 是否預先分配一塊內存用於堆棧和堆,然后根據請求分配? 原始內存是否來自 RAM?

可以在堆而不是堆棧上分配函數嗎?

澄清

我真的在問堆和堆棧內存的實現和管理。 閱讀參考問題后,我沒有找到任何可以解決的問題...感謝鏈接

現代操作系統不允許您直接訪問硬件 RAM,而是將其抽象到所謂的虛擬內存中,並按需映射到 RAM。 每個進程通常都有自己的完整地址空間的私有副本。 這允許操作系統在運行時在 RAM 中移動進程的內存,甚至將其交換到磁盤。 這是透明地發生的,即一個進程不會被通知這樣的重定位並且不需要有代碼來處理這個。 (一些實時應用程序可能會使用技術來防止其內存被換出)。

將目標文件鏈接到可執行文件或動態庫時,鏈接器為函數/方法的 cpu 指令和所有全局變量靜態分配內存。 當操作系統加載可執行文件或動態庫時,它將預先分配的內存映射到實際內存中。

在啟動時,每個線程都會收到一個稱為堆棧的私有內存區域。 每次調用函數/方法時,編譯器都會插入代碼以自動從堆棧分配(通過遞增堆棧指針)足夠的內存來保存函數/方法使用的所有參數、局部變量和返回值(如果有)。 如果編譯器確定將一些變量留在處理器寄存器中就足夠了,它不會在堆棧上為其分配內存。 當函數/方法返回時,它運行編譯器生成的代碼以釋放(通過遞減堆棧指針)該內存。 請注意,堆棧上任何對象的析構函數將在它們定義的塊退出時被調用,這可能需要很長時間才能返回。 此外,編譯器可以自由地重用分配的內存,因為它認為合適。

當拋出異常時,編譯器會插入特殊代碼,該代碼知道堆棧的布局,並且可以展開它,直到找到合適的異常處理程序。

與此相反,堆上的內存使用new / delete分配,編譯器為此插入代碼以使用系統庫請求或釋放內存。

請注意,這是一個簡化的描述,讓您了解內存分配的工作原理。

基本上堆不是由編譯器實現的,而是由 C 運行時庫實現的。 顯然,此代碼非常依賴於平台。 在 Unix 或類 Unix 系統上,實現通常基於 sbrk/brk 系統調用,並分配更大的內存以減少系統調用的數量。 然后由堆內存管理器管理此內存。 如果需要更多內存,則會發出對 sbrk 的新調用。 如果您對調試堆管理例程感興趣,可以使用 sbrk(0) 獲得堆的當前結束地址。 大多數內存管理器在進程的生命周期內不將內存返回給操作系統(如果滿足某些約束,gnu c 運行時庫會這樣做)。

http://gee.cs.oswego.edu/dl/html/malloc.html中提供了更詳細的描述。

一些非常有趣的閱讀

Arm C 和 C++ 庫和浮點支持用戶指南

2.13.2 為內存分配函數選擇堆實現

malloc()、realloc()、calloc() 和 free() 建立在堆抽象數據類型之上。 您可以在 Heap1 或 Heap2 之間進行選擇,這兩種提供的堆實現。

可用的堆實現有:

  • Heap1是默認實現,實現了最小和最簡單的堆管理器。

  • Heap2提供了一種實現,malloc() 或 free() 的性能成本隨空閑塊的數量呈對數增長。

Heap1是默認實現,實現了最小和最簡單的堆管理器。 堆被管理為以遞增地址順序保存的空閑塊的單鏈表。 此實現具有低開銷。 但是,malloc() 或 free() 的性能成本會隨着空閑塊的數量線性增長,並且對於某些用例來說可能太慢了。

如果您預計有超過 100 個未分配的塊,Arm 建議您在需要接近恆定時間的性能時使用 Heap2。

Heap2提供了一種實現,malloc() 或 free() 的性能成本隨空閑塊的數量呈對數增長。 當您在存在數百個空閑塊的情況下需要接近恆定時間的性能時,建議使用 Heap2。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM