天天看點

JavaScript深入之記憶體空間詳細圖解

JavaScript深入之記憶體空間詳細圖解

堆棧的内容和執行順序我就不說了,前面兩篇已經介紹過了。

【進階1-1期】了解javascript 中的執行上下文和執行棧

【進階1-2期】javascript深入之執行上下文棧和變量對象

JavaScript深入之記憶體空間詳細圖解

但是今天補充一個知識點:某些情況下,調用堆棧中函數調用的數量超出了調用堆棧的實際大小,浏覽器會抛出一個錯誤終止運作。

對于下面的遞歸就會無限制的執行下去,直到超出調用堆棧的實際大小,這個是浏覽器定義的。

JavaScript深入之記憶體空間詳細圖解

現在正式開始今天的主題,記憶體空間詳解

棧的結構就是後進先出(lifo),如果讀過前面兩篇文章應該是相當熟悉了。文中使用乒乓球盒子的結構來解釋。

處于盒子中最頂層的乒乓球5,它一定是最後被放進去,但可以最先被使用。而我們想要使用底層的乒乓球1,就必須将上面的4個乒乓球取出來,讓乒乓球1處于盒子頂層。

JavaScript深入之記憶體空間詳細圖解

堆資料結構是一種樹狀結構。它的存取資料的方式與書架和書非常相似。我們隻需要知道書的名字就可以直接取出書了,并不需要把上面的書取出來。json格式的資料中,我們存儲的<code>key-value</code>可以是無序的,因為順序的不同并不影響我們的使用,我們隻需要關心書的名字。

隊列是一種先進先出(fifo)的資料結構,這是事件循環(event loop)的基礎結構,事件循環我們會在第8期詳解介紹。

JavaScript深入之記憶體空間詳細圖解

首先我們應該知道記憶體中有棧和堆,那麼變量應該存放在哪裡呢,堆?棧?

1、基本類型 --&gt; 儲存在棧記憶體中,因為這些類型在記憶體中分别占有固定大小的空間,通過按值來通路。基本類型一共有6種:undefined、null、boolean、number 、string和symbol

2、引用類型 --&gt; 儲存在堆記憶體中,因為這種值的大小不固定,是以不能把它們儲存到棧記憶體中,但記憶體位址大小的固定的,是以儲存在堆記憶體中,在棧記憶體中存放的隻是該對象的通路位址。當查詢引用類型的變量時, 先從棧中讀取記憶體位址, 然後再通過位址找到堆中的值。對于這種,我們把它叫做按引用通路。

JavaScript深入之記憶體空間詳細圖解

在計算機的資料結構中,棧比堆的運算速度快,object是一個複雜的結構且可以擴充:數組可擴充,對象可添加屬性,都可以增删改查。将他們放在堆中是為了不影響棧的效率。而是通過引用的方式查找到堆中的實際對象再進行操作。是以查找引用類型值的時候先去棧查找再去堆查找。

問題1:

問題2:

問題3:

現在來解答一下,三個問題的答案分别是<code>20</code>、<code>‘進階’</code>、<code>{ name: '前端開發' }</code>

對于問題1,a、b都是基本類型,它們的值是存儲在棧中的,a、b分别有各自獨立的棧空間,是以修改了b的值以後,a的值并不會發生變化。

對于問題2,a、b都是引用類型,棧記憶體中存放位址指向堆記憶體中的對象,引用類型的複制會為新的變量自動配置設定一個新的值儲存在變量對象中,但隻是引用類型的一個位址指針而已,實際指向的是同一個對象,是以修改<code>b.name</code>的值後,相應的<code>a.name</code>也就發生了改變。

對于問題3,首先要說明的是<code>null</code>是基本類型,<code>a = null</code>之後隻是把a存儲在棧記憶體中位址改變成了基本類型null,并不會影響堆記憶體中的對象,是以b的值不受影響。

javascript的記憶體生命周期是

1、配置設定你所需要的記憶體

2、使用配置設定到的記憶體(讀、寫)

3、不需要時将其釋放、歸還

javascript有自動垃圾收集機制,最常用的是通過标記清除的算法來找到哪些對象是不再繼續使用的,使用<code>a = null</code>其實僅僅隻是做了一個釋放引用的操作,讓 a 原本對應的值失去引用,脫離執行環境,這個值會在下一次垃圾收集器執行操作時被找到并釋放。

在局部作用域中,當函數執行完畢,局部變量也就沒有存在的必要了,是以垃圾收集器很容易做出判斷并回收。但是全局變量什麼時候需要自動釋放記憶體空間則很難判斷,是以在開發中,需要盡量避免使用全局變量。

前端基礎進階(一):記憶體空間詳細圖解 解讀 javascript 之引擎、運作時和堆棧調用 javascript變量——棧記憶體or堆記憶體
JavaScript深入之記憶體空間詳細圖解