2011-11-17 173 views
25

可能重複:
What and where are the stack and heap爲什麼內存分成堆棧和堆?

我有一對夫婦的堆棧與堆問題。

要知道的基本知識是堆棧比堆快,但是有限。 (如我錯了請糾正我)。

但是,我總是想知道堆棧和堆棧是如何工作的。 RAM只是一塊內存,它不會被分成'堆棧'和'堆'(或者它是什麼?)。如果是這樣,爲什麼我們將堆棧中的內存和堆棧分開?

OS的可能只是讓我們能在棧上分配的一切 - >一切進展快 - >幸福的世界?

我很確定情況並非如此。但爲什麼!?任何人都可以給我一個深入的答案嗎?

很抱歉,如果這個職位是一些後有史以來的人提出的重複,有這麼多相關的棧和堆,我無法找到確切的問題,我有。如果你碰巧知道一個,請繼續並鏈接它。

+3

http://stackoverflow.com/questions/7123936/why-is-there-a-stack-and-a-heap – drdwilcox

+2

http://stackoverflow.com/questions/79923/what-and-where-are堆棧和堆 –

回答

6

你不僅可以使用堆棧,因爲棧需要一個後進先出分配&釋放順序(即你只能取消分配最新的分配數據;在堆棧你不能解除分配一些舊的數據,並保持一定更新的)。

其實,你可以擺脫堆棧(只保留堆)。請參閱Appel的論文Garbage Collection Can Be Faster Than Stack Allocation和他的Compiling with Continuation書。

和堆不具有良好定義的含義(不是「動態分配的存儲器,它是未在堆棧上」以外)。其實,在Linux系統中,分配的使用mmap系統調用內存中的很大一部分是相當快的(但malloc實現儘量避免mmap,寧願重用free -d內存)。問題是分配小內存區域。

並閱讀更多關於garbage collection techniques。在C或C++中,你可以使用Boehm's GC

堆棧通常很有用,尤其是遞歸函數調用。它非常有用(例如在C中)今天的處理器通常具有專用堆棧指針寄存器(由CALL & RET機器指令使用,用於呼叫&返回)。但情況並非總是如此;在一些處理器(例如IBM360)上,堆棧指針是一個傳統的寄存器,而不是硬編碼的。

+0

非常有用的信息,謝謝:) – xcrypt

0

存儲器僅僅是兩者的相同,但棧和堆是用於不同目的的兩個不同的數據結構。

堆棧是受任何微處理器以一對夫婦操作數(通常是處理器的寄存器或存儲器地址)的執行指令需要一個非常原始的抽象。

堆是一個通用分配內存區域,通常你想要存儲沒有綁定到堆棧的數據,也就是說,如果它們存儲在堆棧中,它們的生存期會更長,或者換言之,數據將要通過代碼的不同部分進行訪問。

+0

那麼,我可以只在主函數堆棧中分配一些對象,並在整個程序中使用它,我不需要堆。你的論點可能是堆棧有限,但我打算提出的問題之一是:爲什麼堆棧有限? (由於上述原因) – xcrypt

+0

堆棧受限制,因爲它從內存空間地址的一個極端增長到另一個極端。如果它是無限的,那麼當出現中斷時(因爲中斷會將CPU狀態保存在堆棧中),您可能會損壞堆中存儲在堆中的日期,因此必須在某處設置人爲限制以避免此情況(這是因爲存在當達到該限制時,着名的「堆棧溢出」消息)。 –

23

堆棧:堆棧被用作臨時暫存區,供當前正在執行的代碼塊以及任何稱爲當前塊的塊和任何稱爲該塊的塊等等使用。當前塊存在時,它所使用的局部變量被遺忘。正如名稱所示,堆棧以後進先出的方式使用。

該堆棧最重要的用途之一是跟蹤當前的調用鏈。當一個函數調用另一個函數時,調用者將下一條指令的地址(返回地址)推入堆棧。當每個函數退出時,它會將其調用者的返回地址從堆棧中彈出,並繼續執行從該地址開始的代碼。它也用於在調用者和被調用者之間傳遞函數參數和返回值。

堆:堆是不同的 - 有沒有特定的順序。如果你想在一段代碼中分配內存,並讓該內存超出塊的末尾,你可以將它分配到堆上。當然,您還需要在某處存儲指針/引用,以便其他代碼可以找到該內存;大多數語言提供住宿。

速度:速度的差異並不是由於內存本身的任何屬性 - 正如你在你的問題中所說的那樣,棧和堆通常都在相同的物理內存中。在堆棧中分配空間很快,原因在於堆棧的LIFO性質:如果將某些東西壓入堆棧,只能有一個地方結束。相比之下,在堆上分配塊需要在內存中找到足夠大的連續空閒區域。堆棧分配可以像單條指令一樣快;堆分配需要調用內存分配功能,如malloc()

靜態與動態:在堆上分配內存是動態的 - 是否分配塊和塊的大小可以根據程序在運行時接收的輸入來確定。在堆上分配的內存區域甚至可以根據需要調整大小。它也可能是也可以動態分配堆棧中的內存(請參閱C標準庫函數alloca()),但是當前函數退出後該內存將立即丟失。堆棧分配通常是靜態的 - 編譯器確定(非註冊)參數,返回數據和本地變量需要多少空間,並且在調用該函數時生成代碼以在堆棧中保留必要的空間。

示例:想象一下,您正在創建一個文字處理器。您無法提前知道文檔的大小,甚至可能同時使用多少個文​​檔。與此同時,只要用戶想讓它們保持打開狀態,就希望用戶的文檔保留在內存中。如果您嘗試爲堆棧中的文檔分配內存,您會發現很難一次打開多個文檔,並且您需要創建一個創建,編輯,保存和關閉文檔的函數。在堆上分配空間允許您創建儘可能多的文檔,每個文檔都根據其包含的數據進行適當的大小設置,並避免將文檔的生命週期與任何特定功能的生命週期掛鉤。

總結:簡而言之,堆棧保存變量的值(有時使用寄存器),而堆用於分配將在當前塊的生命週期之外使用的內存。

+0

你能舉個例子說明我被迫使用堆的一些觀點嗎?例如,我可以在父函數中爲整個程序分配堆棧中的所有內容,並通過地址將所有內容傳遞給子函數。 編輯:爲了這個問題,讓我們忽略堆棧受限於RAM內存已滿的其他內容。 – xcrypt

+0

@xcrypt這需要您事先知道您的程序可能執行的每個內存分配。或者,您可以在您的堆棧中分配一個巨大的塊,以後可以動態分配內存。該塊將是堆的功能等同物。我將在上面添加一個示例。 – Caleb

+0

您提到編譯器會在運行前計算出它需要的堆棧空間量,對嗎?遞歸的情況也適用嗎?因爲如果這是正確的,那麼在編譯代碼之後編譯器是否能夠立即提示無限遞歸呢? – Dubby