JavaScript學習系列之記憶體模型篇

來源:互聯網
上載者:User

標籤:賦值   並且   頁面   地址   console   需要   之間   橢圓   語言   

一個熱愛技術的菜鳥...用點滴的積累鑄就明日的達人

本文  如果真的想學好一門語言,那麼一定要瞭解它記憶體模型,本篇文章就帶你走進JavaScript的記憶體模型,由於本人才疏學淺,若有什麼表述有誤的地方,歡迎各位看官能夠指點一二,在此不勝感激...  在閱讀這邊文章之前,預設您已經掌握了JavaScript的基本概念、棧堆等基本資料結構以及電腦基本理論基礎,如有瞭解欠缺,請移步相關部落格後再閱讀本文。一、基本的資料類型的記憶體結構  首先粗略的介紹一下JavaScript中五種基本的資料類型Undefined、Null、Boolean、Number、String;其中對於Undefined與Null的區別,網上有很多大牛都有介紹,在此本文暫不涉及,如有疑慮之處,請移步相關部落格。或許有看官會問為什麼在介紹JavaScript記憶體模型之前要先介紹JavaScript的基礎資料型別 (Elementary Data Type)的記憶體結構呢?這是因為JavaScript記憶體模型與基礎資料型別 (Elementary Data Type)的記憶體結構的關係就好比數學與實數的關係,基礎資料型別 (Elementary Data Type)的記憶體結構是整個JavaScript記憶體模型的基礎。那麼接下來就讓我以最簡短的方式來闡述一下基礎資料型別 (Elementary Data Type)的記憶體結構吧~  基礎資料型別 (Elementary Data Type)的記憶體結構:在JavaScript中基本的資料類型都是以值的形式儲存在記憶體中的。舉個例子: 
var inta = 10;var strb = ‘Hello‘;

  那麼在執行完這段JavaScript代碼之後,記憶體中會有兩個地區分別表示為inta,strb;其中表示inta地區的值為‘10’,表示strb地區的值為‘Hello’,也即表示inta與strb的記憶體地區儲存的均為實際的真值; 

二、引用資料類型的記憶體結構

  在JavaScript中除了基礎資料型別 (Elementary Data Type),那就剩下引用資料類型了,所以在介紹玩基礎資料型別 (Elementary Data Type)記憶體結構之後,就很有必要再介紹一下引用資料類型記憶體結構。引用資料類型的真實對象是儲存在堆記憶體中的,而JavaScript與Java相似,均不可以直接存取堆記憶體,所以都是使用“引用”這個東西來訪問處於堆中的對象,引用與對象的關係可以描述成遙控器與電視機之間的關係,我們可以持有遙控器來操控電視機。所謂的引用其實就是一塊記憶體的地址,即在表示引用的地區上儲存的是記憶體中對象的記憶體位址值,:

  其中假設對象處於記憶體中一個位置叫做0x23215的地區,那麼橢圓的地區表示這個對象的引用,橢圓地區中存的就是0x23125這個值,在實際的操作中執行環境會通過引用中存的0x23125,去找到記憶體中的這個對象。

三、記憶體模型

  在JavaScript執行時期,可以將記憶體從邏輯上劃分為兩部分:棧與堆。其中棧是在JavaScript執行時,用於儲存執行內容(後續文章會介紹)的,而堆是儲存物件的地區。在執行內容產生之後,會建立一個變數對象(後續文章會介紹),變數對象是一個特殊的對象,它也會儲存在堆。基礎資料型別 (Elementary Data Type)往往都會直接儲存在變數對象中,而引用資料類型實際上是在變數對象中儲存一個引用指向對象的地址(也即引用本身)。

 

  學習完JavaScript中的記憶體模型之後,請各位看官看看下面這段代碼,並且猜猜它的輸出結果,以驗證上述知識的理解程度:

var inta = 10;var stra = ‘Hello‘;var obja = {a: 10, b: ‘Hello‘};var intb = inta;var strb = stra;var objb = obja;intb = 20;strb = ‘World‘;objb.a = 20;objb.b = ‘World‘;console.log(inta, intb);console.log(stra, strb);console.log(obja, objb);

  運行結果:

10 20Hello World{ a: 20, b: ‘World‘ } { a: 20, b: ‘World‘ }

  這其中會涉及到對象的賦值問題,在對基礎資料型別 (Elementary Data Type)賦值的時候,都是將原值賦值到新的對象上,所以改變新的對象的值,並不會影響到原值(因為它們本質上儲存的是兩個值);而對引用資料類型賦值則是將引用所指向對象的地址賦值給另一個引用,而在後續操作中,如果通過新的引用去改變對象中內部的值的話,還是會影響原來的引用所指向的對象(因為它們本質上儲存的是同一個對象)

四、記憶體回收機制

  JavaScript具有自動的記憶體回收機制,也即執行環境會負責代碼的執行過程中使用的記憶體,它會定期(周期性)找出哪些不再使用的對象,然後釋放其記憶體。目前JavaScript最常用的記憶體回收演算法為標記清除演算法,記憶體回收機制會通過標記的演算法來決定哪些對象是不需要再次使用的,然後再進行清除,也即清理哪些被定義為垃圾的JavaScript對象。

  上述所述的不再使用的變數也就是生命週期結束的變數,當然只可能是局部變數。全域變數的生命週期直到瀏覽器卸載頁面才會結束,所以聲明一個全域變數的時候,我們一定要謹慎的考慮,在使用完這個變數的對象之後,我們是否還在需要這個對象,如果不需要的話,我們應該手動的將這個變數置為空白,這樣在下一次記憶體回收的時候,就能去釋放這個變數上一次指向的對象(請注意變數與對象的區別)。

  下面請各位看官see一下以下的代碼,來分析一下記憶體回收。

function fun1() {    var obj = {name: ‘csa‘, age: 24};}function fun2() {    var obj = {name: ‘coder‘, age: 2}    return obj;}var f1 = fun1();var f2 = fun2();

  在上述代碼中,當執行var f1 = fun1();的時候,執行環境會建立一個{name:‘csa‘, age:24}這個對象,當執行var f2 = fun2();的時候,執行環境會建立一個{name:‘coder‘, age=2}這個對象,然後在下一次記憶體回收來臨的時候,會釋放{name:‘csa‘, age:24}這個對象的記憶體,但並不會釋放{name:‘coder‘, age:2}這個對象的記憶體。這就是因為在fun2()函數中將{name:‘coder, age:2‘}這個對象返回,並且將其引用賦值給了f2變數,又由於f2這個對象屬於全域變數,所以在頁面沒有卸載的情況下,f2所指向的對象{name:‘coder‘, age:2}是不會被回收的。

  由於JavaScript語言的特殊性(閉包...),導致如何判斷一個對象是否會被回收的問題上變的異常艱難,這不僅需要我們有很強的基本功,還需要在以後的項目中積累經驗。最後順便說一句,即使隨著硬體的更新換代以及記憶體回收機制的改進,我們也不應該忽視記憶體回收的基本理論,因為這是提高代碼效能的關鍵一步,只有這樣我們才能寫出那些堪稱藝術品的代碼...

JavaScript學習系列之記憶體模型篇

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.