來源:互聯網
上載者:User
關鍵字
php
c
java
資料結構和演算法
記憶體
這是百科的解釋,java可以換成任何程式設計語言 :C/PHP/Python
就好像我們在頁面最頂部設定了一個變數
$a = 1;(入)$b = 2;(入)print_r($a);print_r($b);
難道$a = 1是到最後才輸出的嗎?
怎麼回事呢?是我理解有誤嗎?
問題:為什麼叫做棧記憶體?難道此記憶體機制使用了棧的原理?
回複內容:
這是百科的解釋,java可以換成任何程式設計語言 :C/PHP/Python
就好像我們在頁面最頂部設定了一個變數
$a = 1;(入)$b = 2;(入)print_r($a);print_r($b);
難道$a = 1是到最後才輸出的嗎?
怎麼回事呢?是我理解有誤嗎?
問題:為什麼叫做棧記憶體?難道此記憶體機制使用了棧的原理?
棧記憶體一般儲存的是函數的調用資訊和函數中申明的變數,因為函數的調用是遞迴的,外層函數一定比內層被調用的函數先載入和執行,而一定等到內層被調用函數結束後才能結束,這個先進後出的機制就是為什麼叫棧記憶體的原因。
PS:在編譯時間編譯器會先收集此函數中所有定義的變數,將他們放在函數最前面申請記憶體,所以他們進出棧的順序不是你在編寫程式時定義的順序,而是在函數執行前進棧,函數執行完成後出棧。
舉個實際的例子吧:
假設某個調用過程是這樣的
void a() { int p = 1; int q = 2;}void b() { int x = 3; int y = 4; a(); int z = 5;}
那麼我們在調用b();
的過程中棧記憶體其實經曆了一下變化:
([a]
、[b]
代表a()
和b()
的基本資料,如程式指標等)
進入b函數時
棧底 < 棧頂
(函數資訊空間進棧)
[b]
為b函數內參數申請空間
棧底 < 棧頂
(參數空間進棧)
[b] < x < y < z
其他動作無關進出棧,略去
進入a函數時 (函數資訊空間進棧)
棧底 < 棧頂
[b] < x < y < z < [a]
為a函數內參數申請空間
棧底 < 棧頂
(參數空間進棧)
[b] < x < y < z < [a] < p < q
完成a函數時 (參數空間出棧)
棧底 < 棧頂
[b] < x < y < z < [a]
退出a函數時 (函數資訊空間出棧)
棧底 < 棧頂
[b] < x < y < z
完成b函數時 (參數空間出棧)
棧底 < 棧頂
[b]
退出b函數時 (函數資訊空間出棧)
棧底 < 棧頂
翻譯害死人,這裡真正的翻譯叫“棧幀”,Stack Frame!
在JVM設計中一個方法是一個大的Stack Frame,當然方法內部還可以有多個小的Stack Frame,這裡不展開討論。
對於一個方法內部的臨時變數而言,是分配在Stack Frame的局部變數表中的(可以理解為一個數組)Local Variable Table
比如這樣一段代碼,就會在將p和q兩個局部變數丟到局部變數表中。當一個方法寫完之後,局部變數表的大小也就隨之確定了下來
void a() { int p = 1; int q = 2;}
接下來說到“棧”,為啥叫Stack Frame,其實這裡表達的是一個Frame,Stack只是這個Frame的修飾定語而已。因為JVM是基於棧來完成指令運算操作的。(這裡你可以去Google下兩種不同的VM實現方式:基於寄存器和基於棧),JVM之所以選擇基於棧來完成指令運算的設計結構,主要是考慮到了平台遷移的因素,因為不同的CPU架構下,寄存器的個數是不確定的,當然你也可以虛擬出寄存器來玩,但整體的實現成本就複雜上來了。
所以,大學的資料結構一定要學好。堆是堆、棧是棧,沒有單獨的堆棧這種資料結構描述。棧幀是幀,不是棧!
也許你需要去看一下CSAPP或者作業系統或者編譯原理(實際上CSAPP就夠XD)了……
這裡的棧與資料結構的棧只是湊巧重名...