栈(Stack) 任何程序执行前,预先分配一固定长度的内存空间
?
內存是什么及其用處,但內存是不能隨便使用的,因為操作系統自己也要使用內存,而且現在的操作系統正常情況下都是多任務操作系統,即可同時執行多個程序,即使只有一個CPU。因此如果不對內存訪問加以節制,可能會破壞另一個程序的運作。比如我在紙上寫了2/3的值,而你未經我同意且未通知我就將那個值擦掉,并寫上5*2的值,結果我后面的所有計算也就出錯了。
因此為了使用一塊內存,需要向操作系統申請,由操作系統統一管理所有程序使用的內存。所以為了記錄一個long類型的數字,先向操作系統申請一塊連續的4字節長的內存空間,然后操作系統就會在內存中查看,看是否還有連續的4個字節長的內存,如果找到,則返回此4字節內存的首地址,然后編譯器編譯的指令將其記錄在前面提到的變量表中,最后就可以用它記錄一些臨時計算結果了。
上面的過程稱為要求操作系統分配一塊內存。這看起來很不錯,但是如果只為了4個字節就要求操作系統搜索一下內存狀況,那么如果需要100個臨時數據,就要求操作系統分配內存100次,很明顯地效率低下(無謂的99次查看內存狀況)。因此C++發現了這個問題,并且操作系統也提出了相應的解決方法,最后提出了如下的解決之道。
棧(Stack) 任何程序執行前,預先分配一固定長度的內存空間,這塊內存空間被稱作棧(這種說法并不準確,但由于實際涉及到線程,在此為了不將問題復雜化才這樣說明),也被叫做堆棧。那么在要求一個4字節內存時,實際是在這個已分配好的內存空間中獲取內存,即內存的維護工作由程序員自己來做,即程序員自己判斷可以使用哪些內存,而不是操作系統,直到已分配的內存用完。
很明顯,上面的工作是由編譯器來做的,不用程序員操心,因此就程序員的角度來看什么事情都沒發生,還是需要像原來那樣向操作系統申請內存,然后再使用。
但工作只是從操作系統變到程序自己而已,要維護內存,依然要耗費CPU的時間,不過要簡單多了,因為不用標記一塊內存是否有人使用,而專門記錄一個地址。此地址以上的內存空間就是有人正在使用的,而此地址以下的內存空間就是無人使用的。之所以是以下的空間為無人使用而不是以上,是當此地址減小到0時就可以知道堆棧溢出了(如果你已經有些基礎,請不要把0認為是虛擬內存地址,關于虛擬內存將會在《C++從零開始(十八)》中進行說明,這里如此解釋只是為了方便理解)。而且CPU還專門對此法提供了支持,給出了兩條指令,轉成匯編語言就是push和pop,表示壓棧和出棧,分別減小和增大那個地址。
而最重要的好處就是由于程序一開始執行時就已經分配了一大塊連續內存,用一個變量記錄這塊連續內存的首地址,然后程序中所有用到的,程序員以為是向操作系統分配的內存都可以通過那個首地址加上相應偏移來得到正確位置,而這很明顯地由編譯器做了。因此實際上等同于在編譯時期(即編譯器編譯程序的時候)就已經分配了內存(注意,實際編譯時期是不能分配內存的,因為分配內存是指程序運行時向操作系統申請內存,而這里由于使用堆棧,則編譯器將生成一些指令,以使得程序一開始就向操作系統申請內存,如果失敗則立刻退出,而如果不退出就表示那些內存已經分配到了,進而代碼中使用首地址加偏移來使用內存也就是有效的),但壞處也就是只能在編譯時期分配內存。
堆(Heap) 上面的工作是編譯器做的,即程序員并不參與堆棧的維護。但上面已經說了,堆棧相當于在編譯時期分配內存,因此一旦計算好某塊內存的偏移,則這塊內存就只能那么大,不能變化了(如果變化會導致其他內存塊的偏移錯誤)。比如要求客戶輸入定單數據,可能有10份定單,也可能有100份定單,如果一開始就定好了內存大小,則可能造成不必要的浪費,又或者內存不夠。
為了解決上面的問題,C++提供了另一個途徑,即允許程序員有兩種向操作系統申請內存的方式。前一種就是在棧上分配,申請的內存大小固定不變。后一種是在堆上分配,申請的內存大小可以在運行的時候變化,不是固定不變的。
那么什么叫堆?在Windows操作系統下,由操作系統分配的內存就叫做堆,而棧可以認為是在程序開始時就分配的堆(這并不準確,但為了不復雜化問題,故如此說明)。因此在堆上就可以分配大小變化的內存塊,因為是運行時期即時分配的內存,而不是編譯時期已計算好大小的內存塊。
轉載于:https://blog.51cto.com/lailjiaaie/878750
總結
以上是生活随笔為你收集整理的栈(Stack) 任何程序执行前,预先分配一固定长度的内存空间的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux ifconfig命令配置ip
- 下一篇: linux mint 13 input