探討javascript內存問題

垃圾收集策略

自動垃圾收集機制原理

執行環境會負責代碼執行過程中使用的內存。
比如var a = 1,會在棧上占有內存
找出不再繼續使用的變量,然后釋放其占用的內存。
垃圾收集器會按照固定的時間間隔(或根據代碼執行中預定的收集時間設置時間間隔),周期性地執行釋放內存操作。

標記清除策略

javascript最常用的垃圾收集方式是標記清除
當變量進入環境,比如

function(){
var a2=111;
}

a2變量將會被標記為“進入環境”
當變量離開環境時,變量會被標記為“離開環境”

垃圾收集器在運行的時候,
會給“進入環境”并存儲在內存中的所有變量加上標記。

var a3=111;

當變量“離開環境”時,

function fn(){
var c = 111;
}
fn()

局部變量在函數執行之后,“離開環境”
環境中的變量和被變量引用的變量的標記都會被去掉。
這些變量將被刪除,
因為環境中的變量已經訪問不到這些變量,
最后完成內存清理工作,銷毀相應變量的內存。
到2008年瀏覽器都用這種標記清除式的垃圾收集策略。

引用計數策略

跟蹤記錄每個值被引用的次數,
當聲明一個變量并將一個引用類型值賦值給該變量時,

var a4 ;
object = new Object()
a4 = object

這個值object的引用次數就是1。
當同一個值由被賦給另一個變量,

var a5;
a5 = object;

該值object的引用次數又加1,引用次數變為2。
相反,
包含這個值object引用的變量a5又被賦予另一值object2,

object2 = new Object();
a5 = object2;

則該值object的引用次數減1,引用次數變為1。
值object2的引用次數加1,引用次數為1 。
當該值object的引用次數為0時,

object3 =new Object()
a4 = object3

則說明沒法再訪問該值了。
實際上并沒有把值new Object()賦予變量object,
上面只是為了更好地理解對該值的引用。
因為IE瀏覽器的一部分對象并不是原生javascript對象,
其BOM、DOM中的對象是使用COM(組件對象模型)實現的,
這部分對象使用引用計數策略,
而原生javascript對象使用標記策略(其它瀏覽器則都使用該策略)

引用計數策略的缺陷
function(){
var element =document.getElementById('box')
var myObject = new Object();
myObject.someElement = element;
element.someObject = myObject;
}
在標記清除策略中,

該函數執行之后,
這兩個變量都離開作用域,兩個變量的標記也都被清除,
因此兩個值所在內存都會被釋放。
但是,

在引用計數策略中,

當函數執行之后,
兩個值仍然被循環引用,引用次數是2,內存不會被釋放,
則該函數在被重復多次調用之后,
因此會導致大量內存被占用而無法回收。
上例中,
element是DOM元素對象,myObject是原生javascript對象
因為DOM元素對象會使用引用計數策略,
所以會導致內存無法回收。

解決方案
myObject.someElement = null;
element.someObject = null;

變量設置為Null,會切斷變量與引用的值的連接。
當垃圾收集器下次運行時,
會刪除這些值,并回收它們占用的內存。

注意

IE9解決了上述缺陷,它將DOM和DOM對象都轉換為了原生的javascript對象。

管理內存

瀏覽器分配到的內存比桌面應用程度少。
導致一個線程中能同時執行的語句數量減少。
優化內存的方式:解除引用
局部變量會在離開執行環境時,
自動被解除引用,釋放內存。
全局變量和全局對象的屬性,則需要手動解除引用,
否則要等垃圾收集器運行時間到時才會解除引用,

function createPerson(name){
var localPerson = new Object();
//局部變量
localPerson.name = name
return localPerson;
}
var globalPerson = createPerson('jack');
//全局變量
globalPerson = null;
//解除對全局的引用,釋放該值內存

當聲明createPerson函數時,
function createPerson(name){...}
引用類型(new Object())的值被局部變量localPerson引用,值存儲到內存,
局部變量localPerson進入環境并被標記。

當執行createPerson函數時,
createPerson('jack')
局部變量localPerson離開環境并清除標記,釋放存儲該值的內存。

var globalPerson = createPerson('jack');,即值賦值給全局變量時,
引用類型(new Object())的值被全局變量globalPerson引用,值存儲到內存,
全局變量globalPerson進入環境并被標記。

globalPerson = null;
全局變量被解除引用,釋放內存。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容