JavaScript之淺談內存空間

JavaScript之淺談內存空間

JavaScipt 內存自動回收機制

在JavaScript中,最獨特的一個特色就是擁有自動的垃圾回收機制(週期性執行),這也就意味者,前端開發人員可以專一於業餘,從而減小在內存的管理,提升開發的效率。javascript

用戶自定義的對象、函數,但這些都是咱們肉眼不可見的,而是依靠在外部的媒介「內存條」中,自動垃圾回收的本質也就是找出已再也不使用的變量、函數,釋放其佔用的內存空間前端

當再也不須要某樣東西時會發生什麼? JavaScript 引擎是如何發現並清理它?java

可達性

JavaScript 中內存管理的主要概念是可達性。api

簡單地說,「可達性」 值就是那些以某種方式可訪問或可用的值,它們被保證存儲在內存中。數據結構

固有的可達值(根)

  • 本地函數的局部變量和參數dom

  • 當前嵌套執行上下文其餘函數的變量和函數函數

  • 全局變量學習

若是引用或者引用鏈能夠經過根訪問到任何其餘值,則認爲該值是可訪問的3d

實際上網頁的元素就是由一個個對象構建成了一個dom樹(特殊的圖結構)(樹結構是單向,圖結構是雙向的,)指針

經過JavaScipt提供的api咱們能夠找到頁面上指定元素的對象,並對其進行操做

每個DOM元素對象均可以看做是一個根,咱們能夠還能夠訪問自身元素的親戚

  • 父元素

  • 兄弟元素

  • 祖先元素

  • 後代元素

單項引用

var user = {
        name : 'EYS',
    }

這裏的箭頭表示一個對象引用,全局變量 "user" 引用對象{name : 'EYS'} user對象中的name屬性存儲了一個基本類型的數據

但若是user的值被覆蓋,則引用丟失

user = null;

如今user變成不可達的狀態,沒有辦法訪問以前的值,他們之間沒有聯繫,就被JavaScript引擎發現他了!!!而後就把他丟到小黑屋去了,自動釋放了它所佔用的內存空間

#### 雙向引用
// user具備對象的引用
    var user = {
      name: "John"
    };
    var admin = user; //引用傳遞

該對象仍然能夠經過 admin 全局變量訪問,因此它在內存中。若是咱們也覆蓋admin,那麼它能夠被釋放。

相互關聯的對象

function marry (man, woman) {
      woman.husban = man;
      man.wife = woman;

      return {
        father: man,
        mother: woman
      }
    }
    let family = marry({
      name: "John"
    }, {
      name: "Ann"
    })

產生的內存結構:

內存中的圖片變成:
如今讓咱們刪除兩個引用:

delete family.father;
    delete family.mother.husband;

僅僅刪除這兩個引用中的一個是不夠的,由於全部對象仍然是可訪問的。

輸出引用可有可無。只有傳入的對象才能使對象可訪問,所以,John 如今是不可訪問的,並將從內存中刪除全部不可訪問的數據。

垃圾回收以後:

可是若是咱們把這兩個都刪除,那麼咱們能夠看到 John 再也不有傳入的引用:

沒法訪問的數據塊

family = null;

可是若是咱們把這兩個都刪除,那麼咱們能夠看到 John 再也不有傳入的引用:

「family」對象已經從根上斷開了連接,再也不有對它的引用,所以下面的整個塊變得不可到達,並將被刪除。

回收過程

標記清除 (推薦)

分爲『進入環境』和『離開環境』

進入環境 : 指變量進入的執行環境
離開環境 : 指變量完成任務,離開了執行的環境

垃圾收集器會在腳本運行的時候給存儲在內存中的全部變量都加上標記

它會去掉環境中的變量以及被環境中的變量引用的變量的標記

而在此以後再被加上標記的變量將被視爲準備刪除的變量,緣由是環境中的變量已經沒法訪問到這些變量了

最後,垃圾收集器完成內存清除工做,銷燬那些帶標記的值並回收它們所佔用的內存空間

引用計數 (不推薦)

含義 : 跟蹤記錄每一個值被引用的次數

  • 當用戶聲明瞭一個變量並將一個引用類型值賦給該變量時,則這個值的應用次數就爲1 【聲明變量並賦值】

  • 若是同一個值又被賦給另外一個變量,則該值的引用次數加 1 【變量的值傳遞】

  • 若是包含這個值引用的變量被覆蓋了,則以前的值的應用次數減1 【覆蓋變量以前的值】

  • 當這個值的引用次數變成 0 時,則說明沒有辦法再訪問這 個值了,於是就能夠將其佔用的內存空間回收回來。 【變量回收】

這種機制其實在js中並不經常使用,由於這種機制會產生循環引用的問題,『循環引用』指的是對象 A 中包含一個指向對象 B 的指針,而對象 B 中也包含一個指向對象 A 的引用。對於像js類的自動回收機制的語言來講,須要額外手動的去釋放內存,其實並不友好。

在學習內存空間以前,咱們須要對三種數據結構有一個清晰的理解。他們分別是堆(heap)棧(stack)隊列(queue)

三種數據結構

1、棧(Stack)數據結構

JavaScript中並無嚴格意義上區分棧內存與堆內存

如JavaScript的執行上下文(關於執行上下文我會在下一篇文章中總結)。執行上下文的執行順序借用了棧數據結構的存取方式(也就是後面咱們會常常提到的函數調用棧)。所以理解棧數據結構的原理與特色十分重要。

JavaScript的數據類型分爲兩種 : 基本類型,引用類型

咱們能夠簡單粗暴的理解 基本類型數據是存儲在棧,引用類型的數據是存儲在堆中,等待變量創建引用關係

要簡單理解棧的存取方式,咱們能夠經過類比乒乓球盒子來分析。以下圖左側。

基本特徵爲 : 先進後出,後進先出

2、堆(Heap)數據結構

堆數據結構是一種樹狀結構。它的存取數據的方式,則與書架與書很是類似。

書雖然也整齊的存放在書架上,可是咱們只要知道書的名字,就能夠很方便的取出咱們想要的書,而不用像從乒乓球盒子裏取乒乓同樣,非得將上面的全部乒乓球拿出來才能取到中間的某一個乒乓球。比如在JSON格式的數據中,咱們存儲的key-value是能夠無序的,由於順序的不一樣並不影響咱們的使用,咱們只須要關心書的名字。

3、隊列

隊列是一種先進先出(FIFO)的數據結構。正如排隊過安檢同樣,排在隊伍前面的人必定是最早過檢的人。用如下的圖示能夠清楚的理解隊列的原理。

相關文章
相關標籤/搜索