解釋執行和直接執行二進制代碼都使用了堆棧結構。那爲何使用棧結構管理函數調用?markdown
一般函數有兩個主要的特性:異步
函數調用者(父函數)的生命週期老是長於被調用者(子函數),而且被調用者(子函數)的生命週期老是先於調用者(父函數)的生命週期結束。在函數資源分配和回收角度看,被調用函數(子函數)的資源分配老是晚於調用函數(父函數),且資源釋放也先於調用函數(父函數)。是一種後進先出LIFO的策略,棧結構也是這種模式,因此用棧來管理函數調用關係。函數
函數在執行過程當中,其內部變量會按照執行順序被壓入到棧中。當父函數內嵌子函數時,子函數調用結束,就會把函數執行權交還給父函數,這個恢復的過程叫恢復現場。學習
恢復現場使用的方法就是在寄存器中保存一個永遠指向當前棧頂的指針,棧頂指針的做用就是告訴你往哪一個位置添加新元素,這個指針一般存放在esp寄存器中。同時增長另外一個ebp寄存器,用來保存當前函數(父函數)的起始位置,這個位置叫棧幀指針。大數據
每一個棧幀對應一個未運行完的函數,棧幀中保存了該函數的返回地址和局部變量。在JS中,函數執行過程也是相似的。調用一個新函數,v8會爲該函數建立棧幀,等函數執行結束以後,銷燬該棧幀。而棧結構的容量是固定的,若是不銷燬,很容易致使棧溢出。spa
棧的缺點是在內存中不能分配一塊連續的較大的空間,因此棧空間是有限的。此時就有了堆空間,用來保存一些大數據。3d
堆空間中的數據不要求連續存放,從堆上分配內存沒有固定模式,能夠在任什麼時候候分配和釋放它。當遇到大數據時,會在堆中分配一塊空間,返回分配後的內存地址,該地址會被保存在棧中。好比下圖中的pp,棧中的地址指向了在堆中分配的空間地址。指針
當堆中的數據再也不須要的時候,須要對其進行銷燬。若是不及時銷燬,容易形成內存泄漏。code
V8相關的學習總結來自於極客時間李兵老師的課程《圖解goole V8》,若是想了解更多細節,能夠進課程查看。orm