JS數據類型轉換與內存模型
面試
一張圖表示,簡單明瞭~
算法
內存分爲RAM和ROM。RAM是隨機存取存儲器,用戶可讀可寫,計算機斷電後,存儲在RAM的信息將被刪除。RAM具體分爲SRAM(Static RAM)和DRAM(Dynamic RAM)。咱們 如今所說的內存通常指的都是DRAM,SRAM速度更快,可是容量相對於其餘類型內存而言也會小一些,而且價格也較爲昂貴。通常SRAM做爲CPU和DRAM之間的緩存(cache)。ROM是隻讀存儲器,ROM的內容是製造商寫進去的,用戶只能讀,但不能寫。ROM在切斷電源後,數據也不會丟失。計算機會給當前執行的程序動態地分配內存空間,例如用戶打開瀏覽器打開諸多網頁,計算機會給瀏覽器分配內存,瀏覽器會給每個頁面分配內存,會給頁面的HTML,CSS,JS分配內存。數組
由於內存中的數據在斷電以後會消失,因此爲了數據的保存,就須要使用其餘類型的存儲器。這類存儲器通常是磁盤,固態硬盤(ssd)等,也就是所謂的外存。瀏覽器
JS中的基礎數據類型每每都保存在棧內存中,由於這些值都有固定的大小。
例如:var a = 1;
內存分配圖大概是這個樣子的:
緩存
var a = {'key':'value'};
內存分配圖大概是這個樣子的:
var a = {n:1};
var b = a;
a.x = a = {n:2};
=============================
問:
console.log(a.x)= ?
console.log(b.x) =?
複製代碼
這道題涉及到了連續賦值的狀況,在程序運行以後,先肯定好了a.x 和 a的引用,而後再從右往左開始賦值 。本題的內存分析以下:
bash
var a = {n:1};
var b = a;
複製代碼
代碼執行到這裏時,內存圖模型以下:
函數
a.x = a = {n:2};
時,JS首先會肯定a在stack中的「地址」也就是指向對象的引用。
a.x = a = {n:2};
// 本例中a在stack中的地址爲addr=31,在肯定好這個信息後,代碼會從右至左開始執行。
複製代碼
首先是a = {n:2}
ui
a.x = a
,在內存模型中,此時左邊的a在stack中對應的地址爲addr31,而右邊的a在stack中的地址已經變爲了addr33。因此這個操做至關於在addr31所指向的對象中添加x屬性,x的屬性值爲addr33指向的對象。
參考內容:JavaScript內存管理一文。spa
引用計數算法定義「垃圾」的標準很簡單,就是看一個對象是否有指向它的引用,若是沒有就回收。可是引用計數算法卻存在着許多問題,試想若是在堆內存中,有對象相互引用,即使是它們再也不使用,可是GC不會進行回收,最後就會致使內存泄漏的問題,而IE6就是使用引用計數算法來進行垃圾回收的。
如代碼:code
function c() {
var o1 = {};
var o2 = {};
o1.a = o2;
o2.a = o1;
return "IE6'Bug"
}
c();
複製代碼
按理來說方法在調用以後,對象o1,o2能夠進行回收了,可是在堆內存中二者互相引用,是根據引用計數算法的定義,在堆內存的這兩個對象還存在着引用的關係,因此這部份內存不會被回收,接下來就有可能帶來內存泄漏的問題。什麼是內存泄漏呢?內存泄漏(Memory Leak) 是指在程序中動態被分配的堆內存中,因爲某種緣由,致使程序未被釋放或者說沒法釋放而形成了系統內存的浪費,進而致使程序運行速度減慢,甚至是系統崩潰。
標記清除算法是現代瀏覽器主要使用,並在此之上加以改進並應用的算法,標記清除算法定義「垃圾」爲從棧內存開始「沒法達到」的對象。對於IE6出現的Bug,即使是堆內存中兩個對象互相引用的狀況,標記清除算法也能夠進行回收。
如:
var a = 1;
var b = a;
複製代碼
這個過程就是深拷貝,對於基本類型來講,賦值的過程就是深拷貝。當咱們嘗試去改變b的值時,變量a的值不會發生變化,換句話說,一個變不會影響另外一個這就是深拷貝。淺拷貝則偏偏相反,對於複雜類型而言:
var a = {name:'a'};
var b = a;
複製代碼
a和b指向同一個對象,當改變a.name或b.name時,另外的引用指向的對象(其實就是本身)會發生改變,因此咱們能夠這麼理解:一個變會影響另外一個變這就是深拷貝。對於複雜類型來講,也能夠經過代碼實現深拷貝,後續再見~