過程是程式的一種抽象,以一組引數和返回值實現對乙個功能的封裝,過程包含的形式有:函式、方法、處理函式等
過程呼叫必須解決的三大機器級別問題:
控制轉移:過程p呼叫過程q,進入過程q時,程式計數器設定為q的**起始位址,在q執行完成返回時,需要把程式計數器設定為p呼叫q位置的下一條指令位址。
引數傳遞:p必須為q提供若干個引數,q可以向q返回乙個值
記憶體分配與釋放:被呼叫過程q可能會為區域性變數分配空間,而在返回前,又需要釋放這些區域性空間。
【執行時棧】
棧資料結構為後進先出,這與函式呼叫過程的呼叫=》進入=》返回 過程是相似的。
當被調過程p被執行時,其呼叫者p之前的過程被暫時掛起。當q執行時,它只需要為其內部的區域性變數分配空間,或者呼叫另外乙個過程,當q返回時,又釋放這些空間,因此程式採取棧和程式暫存器來存放控制轉移和資料,以及記憶體分配資訊。
x86-64架構的棧由高位址向低位址增長,棧頂指標%rsp暫存器始終存放棧頂的位址,而pushq 和popq指令則對應棧的入棧和出棧。分配空間,棧頂指標減小,釋放空間,棧頂指標增大。
通常而言,對於過程中的儲存空間,優先分配在暫存器組中(速度更快),通常過程6個或更少的引數,均可以通過暫存器存放,當空間不夠時,再分配在棧記憶體中。分配在記憶體中的部分即為上述的棧幀。過程p呼叫過程q 時,會首先把返回位址壓人棧中,指明當q返回後,呼叫者p從下一條哪個位置繼續執行。
【資料傳送】
過程呼叫中,除了要進行控制轉移外,還需要進行引數傳遞和過程返回。在x86-64中,大部分呼叫過程的資料傳輸通過暫存器實現。而當被呼叫過程返回前,其將返回值寫入暫存器中(%rax)呼叫者通過暫存器獲取到這個返回值。
當引數的數量較大以至於暫存器無法存放時,採取棧幀中的引數構造區來進行引數傳遞。
【區域性儲存】
引數傳遞可以採取暫存器組進行實現,但當區域性資料更為複雜時,必須在記憶體中進行空間分配:
可以了解到,引數的傳遞存放以及區域性變數可以採取記憶體或者暫存器的物理方式進行儲存。而由於暫存器組的數量有限,若呼叫過程很複雜(遞迴呼叫等)需要有乙個約定,即:
被呼叫者的活動不會覆蓋呼叫者會使用的暫存器值。
因此在被調過程q執行過程中,其通過幾種方式以確保這些約定:
過程q保證暫存器的值不變,或者不去使用它
過程q使用前先暫時將暫存器的值到記憶體,在使用完畢後即返回前,將暫存器的值恢復。
呼叫很浪費執行時間
克林在打一行字母時總是會打多乙個字元,比如想打 july 時會打成 juuly 這樣他需要刪掉其中乙個 u 克林想知道他可以刪掉哪個位置的字元就可以變成他真正想打的一行字母。第一行乙個整數 t 測試個數 每個測試 輸入兩行,兩個字串 全是小寫字母 串長為 1 到 1000000 第乙個串長度剛好比第...
執行時異常
常見的幾種如下 nullpointerexception 空指標引用異常 classcastexception 型別強制轉換異常。illegalargumentexception 傳遞非法引數異常。arithmeticexception 算術運算異常 arraystoreexception 向陣列中...
linux抓取執行時程序棧資訊
linux上開發時,一般程序執行結果和預期不符會通過打log記錄日誌分析執行過程,但有時log日誌不全,再者一些大型系統長期執行不會過多的記錄日誌,一般可以設定core檔案配置,以便程序在異常掛掉後自動記錄棧資訊,但大部分情況下程序是在執行過程中出現問題,這時就需要抓取執行時棧資訊,結合日誌進行分析...