內存為啥要分堆棧在編程裡,要是全部只用堆或者全部只用棧,行不行?

Z-jane


其實我們都知道,計算機內存本來就是一塊內存,沒有堆棧之分。

在學編程的時候,我們應該都聽過一句話 “如果程序結束之後仍然想要訪問那一段數據就要用堆”,我想這個其實就是你疑問的關鍵了,堆和棧都有其自己的獨特性,可能你瞭解這兩個東西,但是我還是解釋下,以免別的小夥伴在看答案的時候,不知道。

棧:就像我第一句話說的,本沒有什麼堆棧之分,但是編程語言的出現,就有了一個概念“函數”,這個函數之間是可以相互調用的(就像我們傳遞東西,比如:胡小然 將東西傳遞 胡小然2 將東西傳遞 胡小然3,之後需要從後面向前面反饋傳遞結果,這個傳遞的過程我們就可以理解為調用),那就出現了前後之分,這就是調用隊列了,那這個隊列有個什麼特點呢,那就是先被調用進入隊列的要最後出去,就是我們常說的先進後出(FILO),那麼這時棧就出現了,而且它還有一個特點那就是線程獨有(所以可以存放我們的臨時變量),生命週期是隨線程的。當然我所說的是內存棧的意思,其實“棧”就是個數據結構,是一種限定僅在表尾進行插入和刪除操作的線性表,這個特性不正好是符合我剛才說的FILO嘛。所以你可以這麼理解c++或者java(jvm)中的內存棧的概念,就是編程語言的作者為了管理內存使用了“棧”這種數據結構(說的再細點就是現代CPU體系結構決定了棧是管理函數調用和局部變量的最佳數據結構。因為CPU已經提供了現成的指令)。

堆:可算是一種特殊的數據結構,好像我們經常使用的二叉樹。內存堆這個解釋起來就更簡單了,就是一塊能自由分配的內存。它允許程序在運行時動態地申請某個大小的內存空間,比如:程序員向操作系統申請一塊內存,當系統收到程序的申請時,會遍歷一個記錄空閒內存地址的鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序。其特點就是分配的速度較慢,地址不連續,容易碎片化並且是由程序員申請,同時也必須由程序員負責銷燬,否則導致內存洩露。像在java這種高級語言中,我們不比擔心內存回收的問題,那是因為jvm已經在幫我們處理了。


上面說了這麼多,就是想說明一下內存棧和內存堆出現的意義和作用,所以答案就出來了,那就是不能“只用堆或者全部只用棧”那樣我們程序的調用和數據的存儲都會出現問題。

好了,上面只是我自己一些理解,不對的地方還請大家指出,也希望對題主的疑問有幫助。


唯一胡小然


一個非常好的問題。堆棧是典型的兩類內存分配方式,都是為了優化內存的使用,各有特點,用在不同的場景中。


一,棧

棧具有先進後出,後進先出特性,連續存儲,操作簡單,使用方便,無需管理,大部分芯片都對棧提供芯片級別的硬件支持,只需要移動指針就可以快速實現內存的分配和回收。比如局部變量使用棧內存,減少不必要的內存分配管理。


棧創建和刪除的時間複雜度是O(1),速度快。但是不利於管理大內存,棧中的數據大小和生存週期都是確定的,缺乏靈活性。


二,堆

堆內存的管理機制相對複雜,有一套相應的分配策略,防止大量小碎片出現,同時加快查找。堆用於動態創建分配內存,創建和刪除節點的時間複雜度是O(logn)。


堆的回收機制也複雜很多,根據內存大小不同,數據生命週期不同,採用相應的回收機制,涉及操作系統的堆管理。


因為堆內存的管理和申請相對複雜,更消耗系統資源,通常生命週期更長使用範圍更廣的全局變量使用堆內存。



急速馬力快de源碼控


堆和棧是不能相互替代的。程序的結構是前部是棧,中部是程序體,後部是堆。前部和中部是鏈接的時候由編譯器算好了的,執行過程中是固定不變的。而後部則可以隨著程序的執行而改變長度。

那麼為什麼要把內存分成堆和棧呢?

棧是用來存儲程序初期設定的變量的,這些變量在程序執行之前就要準備好。因此棧要放在程序的前部並且固定位置,否則程序就不知道該到那裡去找這些變量。而程序的運行結果往往是不能預先確定的,所以把堆放在後部以便可以提供足夠的內存保存運算結果。

至於棧用先進後出的方式,讀寫速度高,這是針對它的長度固定的特徵設計出來的。而堆為了保持可擴張的特性,也設計了類似於二叉樹的索引方式,以便可以高速地尋址,並可以方便地釋放內存空間。


分享到:


相關文章: