簡體   English   中英

關於C / C ++堆棧分配

[英]About C/C++ stack allocation

在學習C ++(和C)時,我對堆棧分配的工作有一些特別的疑問,我無法找到解決方案:

  1. 堆棧分配是否隱式調用malloc / free函數? 如果不; 它如何確保堆棧分配和堆分配之間沒有沖突?

  2. 如是; C ++中的堆棧分配是否也隱式調用new / delete? 如是; 重載一個類的new運算符會影響它的堆棧分配嗎?

它在VC ++中產生了令人困惑的結果; 但由於VC ++並不完全符合標准(或者我聽說過),我決定在這里問一下......

堆棧分配不使用malloc / free之類的東西。 它使用一段稱為程序堆棧的內存,它只是一段連續的內存。

有一個特殊的寄存器存儲堆棧的頂部。 當在堆棧上創建新對象時,頂部被抬起從而增加堆棧,當對象被解除分配(超出范圍)時,頂部被降低從而減少堆棧。

如果您嘗試在堆棧上分配太大的對象或者過於深入遞歸,則頂部將超出堆棧的最大允許大小,這稱為堆棧溢出。

注意:堆棧增長的實際方向(增加或減少地址) 將因系統而異 ,但無論實際方向如何,總體思路都是相同的。

第一個問題的答案是否。堆棧根本沒有從堆中分配。

您應該首先閱讀堆棧和堆的內容和位置以了解基本概念。

堆棧分配通常根據alloca()或由編譯器隱式完成。 一個做得好的alloca()只需要很少的指令,並且在你完成時沒有任何成本(甚至是需要)來釋放它。

您可以將指向alloca()分配的內存的指針傳遞給任何其他需要指針的函數/方法。 你必須永遠不要返回alloca()分配的指針。

以下是使用堆棧分配的一些優點缺點

這里有一個很好的問題:

“它如何確保堆棧分配和堆分配之間沒有沖突?”

幾乎所有C / C ++實現中都有一個連續的地址空間,因此堆棧和堆分配的內存必須在該空間中共存。

雖然每次堆棧增長和收縮時都不會使用單個堆分配,但您仍然可以將堆棧視為從堆分配的單個大塊內存。 如果堆棧超出了該塊的邊界,那么我們就會有一個堆棧溢出(引人注目的名字......有人應該在它之后命名一個網站)。

在多線程程序中,每次線程啟動時,都必須為它分配一個新堆棧,當線程死亡時,可以釋放堆棧。 並且使用與通過malloc / free公開的相同堆管理來分配整個堆棧塊是有意義的。

所以 - 非常接近 - 你可以認為堆棧是一種在堆中共存的對象。 當一個線程啟動時,整個堆棧都是malloc -ed,然后它會從中進行子分配,然后一次性free -d。

在Windows上,您可以(如果您喜歡危險地生活) 自己調用相同的虛擬內存API來查找堆棧並強制釋放其中的虛擬頁面。

在C和C ++中,存在兩種類型的內存分配“自動”,其中對象是在函數調用的生命周期中創建的,而“動態”則是由運行時提供的函數分配的。

在絕大多數運行時實現中,在創建線程時使用操作系統提供的連續堆棧分配自動對象。 堆棧通常從高值地址開始,並按對象的大小遞減。 動態分配(C中的malloc,C ++中的new)使用操作系統請求的其他一些內存。 由於操作系統知道堆棧正在使用的地址,因此它不會為動態請求分配相同的地址。 由於動態區域沒有排序,因此通常稱為堆。

所以'堆棧'分配不是malloc / free。 C ++中的自動對象調用構造函數和析構函數,但不是new或delete,因為new和delete也有管理動態內存的代碼。

不,堆棧分配不會調用malloc / free。 整個堆棧空間在程序開始時分配。 在進入每個函數時,堆棧指針足夠高,以允許堆棧上的空間為“堆棧幀”,這將是堆棧分配變量所在的位置。

Kepp記住“堆棧分配”是一個實現細節。 無法保證堆棧用於自動存儲。 例如,傳說中的IBM大型機沒有(雖然我被告知他們更現代的機器)。

暫無
暫無

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

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