因爲字符串、對象和數組沒有固定大小,因此當他們的大小已知時,才能對他們進行動態的存儲分配。JavaScript程序每次建立字符串、數組或對象時,解釋器都必須分配內存來存儲那個實體。只要像這樣動態地分配了內存,最終都要釋放這些內存以便他們可以被再用,不然,JavaScript的解釋器將會消耗完系統中全部可用的內存,形成系統崩潰。 ---《JavaScript權威指南(第四版)》javascript
JavaScript的解釋器能夠檢測到什麼時候程序再也不使用一個對象了,當他肯定了一個對象是無用的時候,他就知道再也不須要這個對象,能夠把它所佔用的內存釋放掉了。例如:java
var a = "before"; var b = "override a"; var a = b; //重寫a
這段代碼運行以後,「before」這個字符串失去了引用(以前是被a引用),系統檢測到這個事實以後,就會釋放該字符串的存儲空間以便這些空間能夠被再利用。node
最常採用的垃圾回收有兩種方法:標記清除、引用計數git
當執行流入到一個函數中時,會建立該函數的執行環境,執行環境中的變量都會被標記爲「進入環境」,從邏輯上講,永遠不能釋放「進入執行環境」變量所佔用的內存。由於只要執行流入相應的執行環境,就可能會用到這些變量。
垃圾收集器在運行的時候會給存儲在內存的中的變量都加上標記。而後,它會去掉環境中的變量以及被環境中的變量引用的變量的標記。而在此以後再被加上標記的變量將被視爲準備刪除的變量。最後,垃圾收集器完成內存清除工做,銷燬那些帶標記的值並回收它們所佔用的內存空間。github
另外一種不太常見的垃圾回收策略是引用計數。引用計數的含義是跟蹤記錄每一個值被引用的次數。當聲明瞭一個變量並將一個引用類型賦值給該變量時,則這個值的引用次數就是1。相反,若是包含對這個值引用的變量又取得了另一個值,則這個值的引用次數就減1。當這個引用次數變成0時,則說明沒有辦法再訪問這個值了,於是就能夠將其所佔的內存空間給收回來。這樣,垃圾收集器下次再運行時,它就會釋放那些引用次數爲0的值所佔的內存。chrome
可是用這種方法存在問題:數組
function problem(){ var objA = new Object() var objB = new Object() objA.someOtherObject = objB objB.someOtherObject = objA }
在這個例子中,objA和objB經過各自的屬性相互引用;也就是說這兩個對象的引用次數都是2。在採用引用計數的策略中,因爲函數執行以後,這兩個對象都離開了做用域,函數執行完成以後,objA和objB還將會繼續存在,由於他們的引用次數永遠不會是0。這樣的相互引用若是說很大量的存在就會致使大量的內存泄露。緩存
將全局變量做爲緩存數據的一種方式,將以後要用到的數據都掛載到全局變量上,用完以後也不手動釋放內存(由於全局變量引用的對象,垃圾回收機制不會自動回收),全局變量逐漸就積累了一些不用的對象,致使內存泄漏閉包
var x = []; function grow() { x.push(new Array(1000000).join('x')); /* 使用x數組進行某些操做 */ setTimeout(grow, 1000); } grow()
(function () { var nodes = ''; var item = { // 爲了凸顯 name: new Array(1000000).join('x') } nodes = document.getElementById("nodes") nodes.item = item nodes.parentElement.removeChild(nodes) })()
notes變量指向的是頁面中的一個元素(也是內存中的一塊空間),當將 notes 對應的元素從頁面中移除後,其在內存中對應的空間因爲仍然由notes變量指向(引用),所以垃圾回收機制不會將這塊內存空間回收,從而致使內存泄漏ide
var someResource = getData(); setInterval(function() { var node = document.getElementById('Node'); if(node) { node.innerHTML = JSON.stringify(someResource)); } }, 1000);
這樣的代碼很常見, 若是id爲Node的元素從DOM中移除, 該定時器仍會存在, 同時, 由於回調函數中包含對someResource的引用, 定時器外面的someResource也不會被釋放.
var theThing = null var replaceThing = function () { var originalThing = theThing var unused = function () { if (originalThing) console.log("hi") } theThing = { longStr: new Array(1000000).join('*'), someMethod: function () { console.log(someMessage) } }; }; setInterval(replaceThing, 1000)
這種內存泄漏的分析請參考here
《JavaScript權威指南》
javascript典型內存泄漏及chrome的排查方法