1、存儲組織
1.1、運行時內存的劃分
在運行時,系統將爲目標程序分配一塊存儲空間,這個存儲空間按用途可以劃分爲下面幾個部分:
( 1 )、目標程序區,用來存放所生成的目標程序;
( 2 )、靜態數據區,用來存放編譯程序本身就可以確定所佔用存儲空間大小的數據;
( 3 )、運行棧區,在運行時才能分配存儲空間的數據就分配在運行棧;
( 4 )、供用戶動態申請存儲空間的堆區。
這幾個部分之間的關係如圖7 - 1所示。當然,並不是所有語言的實現都需要這些區域。
圖7-1 運行時內存分配示意圖
由於編譯程序所生成的目標代碼的長度在編譯時(至遲在連接之後)就能確定,因此可以把它放在一個靜態確定的區域內。同樣,若一些數據對象的大小在編譯時是已知的,它們也可以放入靜態確定的存儲區域內。應儘可能多地對數據對象進行靜態分配,以縮短運行時間。例如,FORTRAN中的所有數據對象都可以進行靜態分配。
像PASCAL和C 之類語言的實現,則宜於使用擴充的棧來管理過程的活動(我們將一個過程的每一次執行稱爲這個過程的一次活動)。當出現一個過程調用時,當前正執行的活動將被打斷,有關機器狀態的信息,如程序計數器的值、返回地址和機器各寄存器的值,應存入棧中。而當控制從一個被調用過程返回時,在恢復了有關寄存器和程序計數器的值之後,被中斷的活動將從斷點繼續執行。
PASCAL和C 允許數據存儲空間在程序控制之下進行分配,這種數據的存儲空間可以從堆中得到。
棧和堆可用空白區的大小將隨程序的執行而變化。在圖7 - 1 中,顯示了棧和堆共用一空白存儲區,並在使用過程中相互迎面地進行調劑的情況。由於PASCAL和C既存在過程的遞歸調用又允許動態申請空間,所以這類語言同時需要運行時的棧和堆。
1.2、活動記錄
一個過程的一次執行所需信息的管理,是通過使用一個所謂活動記錄的連續存儲塊來實現的。活動記錄中可包括如圖7 -2 所示的各個域。在PASCAL和C 語言中,我們通常採用以過程爲單位的動態存儲分配方案,即當一個過程被調用時,就把它的活動記錄推入運行時存儲棧的桟頂,而在控制返回調用程序時,再從桟頂彈出相應的活動記錄。
圖7-2 一個常用的活動記錄
活動記錄中各種域的作用如下:
( 1 )、臨時變量域——用來存放目標程序臨時變量的值,如計算表達式時所產生的結果;
( 2 )、局部數據域——用來存放過程本次執行中的局部數據、簡單變量以及數組內情向量等;
( 3 )、機器狀態域——用來保存在調用一個過程之前有關機器狀態的信息,其中包括各種寄存器的當前值和返回地址等;
( 4 )、任選的存取鏈——爲訪問其它活動記錄中所存放的非局部數據提供鏈地址(這在PASCAL語言中是需要用到的);
( 5 )、任選的控制鏈——用以指向主調過程的活動記錄;
( 6 )、實在參數——用於存放主調過程爲被調用過程所提供的實在參數信息(在活動記錄中,我們列出了實在參數的存放空間,但是爲了提高效率,有時參數是通過機器寄存器來傳遞的);
( 7 )、返回值域——被調用過程用來爲主調過程存放返回值的域。
每個活動記錄都可分爲定長部分和可變部分。定長部分用來存放那些在編譯時就能確定其體積的量,如簡單變量、常界數組等;可變部分用來存放只有在運行時,才能確定其體積的量,如可變數組、動態指針等。雖然只有在運行時,才能爲這些可變體積的數據在活動記錄的可變部分分配其存儲空間,但在編譯時卻能產生通過活動記錄的首地址(一般用一個指示器指示)來訪問它們的目標代碼,這是因爲在該活動記錄的定長部分,已設定了存放確定其體積的有關信息的域(如數組的內情向量),而這些域在活動記錄中的相對位置是恆定的。