本篇文章講解JavaScript 中垃圾回收機制,內存泄漏,結合一些常遇到的例子,相信各位看完後,會對JS 中垃圾回收機制有個深刻的瞭解。node
首先,無論什麼程序語言,內存生命週期基本是一致的:github
在全部語言中第一和第二部分都很清晰。最後一步在低級語言中(C語言等)很清晰,可是在像JavaScript 等高級語言中,這一步是隱藏的、透明的。由於JavaScript 具備自動垃圾收集機制(Garbage collected )。在編寫 JS 時,不須要關心內存使用問題,所需內存分配以及無用內存的回收徹底實現了自動管理。web
內存泄漏(memory leaks),什麼狀況下回致使內存泄漏?能夠簡單理解爲有些代碼原本要被回收的,但沒有被回收,還一直佔用着操做系統內存,從而越積越多,最終會致使內存泄漏(能夠理解爲,內存滿了,就溢出了)。算法
分配給web瀏覽器的可用內存數量一般要比分配給桌面應用程序少。這樣作的目的主要是處於安全方面考慮,目的是防止運行JS 的網頁耗盡所有系統內存而致使系統崩潰。內存限制問題不只會影響給變量分配內存,同時還會影響調用棧以及在一個線程中可以同時執行的語句數量。chrome
所以,確保佔用最少的內存可讓頁面得到更好的性能。而優化內存佔用的最佳方式,就是爲執行中的代碼只保存必要的數據。一旦數據再也不有用,最好經過將其值設置爲 null 來釋放其引用。這個方法叫作解除引用。這一作法適用於大多數的全局變量和全局對象的屬性。局部變量會在他們離開執行環境時自動被解除引用。瀏覽器
解除一個值的引用並不意味着自動回收改值所佔用的內存。解除引用的真正做用是讓值脫離執行環境,以便垃圾收集器下次運行時將其回收。安全
一般,垃圾收集器(garbage collector)在運行時候會給儲存在內存中的全部變量都加上標記。而後,它會去掉環境中的變量以及被環境中的變量引用的變量的標記。而在此以後再被加上標記的變量將被視爲準備刪除的變量,緣由是環境中的變量已經沒法訪問到這些變量了。最後,垃圾收集器完成內存清除的工做。ide
那標記清除具體是如何呢?有如下幾種算法:函數
var n = 123; // 給數值變量分配內存 var s = "azerty"; // 給字符串分配內存 // 給對象及其包含的值分配內存 var o = { a: 1, b: null }; // 給函數(可調用的對象)分配內存 function f(a){ return a + 2; }
function foo(arg) { // 此處bar 是全局變量,window.bar 能夠訪問,因此也不會被回收 bar = "this is a hidden global variable"; } function foo() { // 此處this 表明 window this.variable = "potential accidental global"; }
var someResource = getData(); setInterval(function() { var node = document.getElementById('Node'); if(node) { node.innerHTML = JSON.stringify(someResource)); } }, 1000); // 上面這段代碼,定時器setInterval 和 someResource 一直存在,不會被回收。能夠改爲下面代碼 var element = document.getElementById('button'); function onClick(event) { element.innerHtml = 'text'; } element.addEventListener('click', onClick); // 手動移除事件監聽器和變量 element.removeEventListener('click', onClick); element.parentNode.removeChild(element);
var intervalId = null, params; function createChunks() { var div, foo, i, str; for (i = 0; i < 20; i++) { div = document.createElement("div"); str = new Array(1000000).join('x'); foo = { str: str, div: div }; div.foo = foo; } } function start() { if (intervalId) { return; } intervalId = setInterval(createChunks, 1000); } function stop() { if (intervalId) { // 清除定時器 clearInterval(intervalId); } // 清除變量 intervalId = null; }
連接觀察垃圾回收是怎麼工做的—Google: Watching the GC work
在上面圖片中,能夠觀察到,點擊 start 按鈕,內存和節點數暴增,當點擊stop 時,垃圾收集器回收了這些定時器、變量等,從而釋放了內存。