原由是由於想了解閉包的內存泄露機制,而後想起《js高級程序設計》中有關於垃圾回收機制的解析,以前沒有很懂,過一年回頭再看就懂了,寫篇博客與你們分享一下。若是喜歡的話能夠點波贊/關注,支持一下。node
我的博客瞭解一下:obkoro1.comgit
因爲字符串、對象等沒有固定的大小,js程序在每次建立字符串、對象的時候,程序都會分配內存來存儲那個實體。github
使用分配到的內存作點什麼。數組
不須要時將其釋放回歸:瀏覽器
在不須要字符串、對象的時候,須要釋放其所佔用的內存,不然將會消耗完系統中全部可用的內存,形成系統崩潰,這就是垃圾回收機制所存在的意義。markdown
所謂的內存泄漏指的是:因爲疏忽或錯誤形成程序未能釋放那些已經再也不使用的內存,形成內存的浪費。閉包
在C和C++之類的語言中,須要手動來管理內存的,這也是形成許多沒必要要問題的根源。幸運的是,在編寫js的過程當中,內存的分配以及內存的回收徹底實現了自動管理,咱們不用操心這種事情。dom
垃圾收集器會按照固定的時間間隔,週期性的找出再也不繼續使用的變量,而後釋放其佔用的內存。函數
什麼叫再也不繼續使用的變量?oop
再也不使用的變量也就是生命週期結束的變量,是局部變量,局部變量只在函數的執行過程當中存在,當函數運行結束,沒有其餘引用(閉包),那麼該變量會被標記回收。
全局變量的生命週期直至瀏覽器卸載頁面纔會結束,也就是說全局變量不會被當成垃圾回收。
工做原理:
當變量進入環境時(例如在函數中聲明一個變量),將這個變量標記爲「進入環境」,當變量離開環境時,則將其標記爲「離開環境」。標記「離開環境」的就回收內存。
工做流程:
到2008年爲止,IE、Chorme、Fireofx、Safari、Opera 都使用標記清除式的垃圾收集策略,只不過垃圾收集的時間間隔互有不一樣。
循環引用:跟蹤記錄每一個值被引用的技術
在老版本的瀏覽器中(對,又是IE),IE9如下BOM和DOM對象就是使用C++以COM對象的形式實現的。
COM的垃圾收集機制採用的就是引用計數策略,這種機制在出現循環引用的時候永遠都釋放不掉內存。
var element = document.getElementById('something');
var myObject = new Object();
myObject.element = element; // element屬性指向dom
element.someThing = myObject; // someThing回指myObject 出現循環引用(兩個對象一直互相包含 一直存在計數)。
複製代碼
解決方式是,當咱們不使用它們的時候,手動切斷連接:
myObject.element = null;
element.someThing = null;
複製代碼
淘汰:
IE9把BOM和DOM對象轉爲了真正的js對象,避免了使用這種垃圾收集策略,消除了IE9如下常見的內存泄漏的主要緣由。
IE7如下有一個聲明狼藉的性能問題,你們瞭解一下:
IE7已修復這個問題。
雖然有垃圾回收機制,但咱們在編寫代碼的時候,有些狀況仍是會形成內存泄漏,瞭解這些狀況,並在編寫程序的時候,注意避免,咱們的程序會更具健壯性。
上文咱們提到了全局變量不會被當成垃圾回收,咱們在編碼中有時會出現下面這種狀況:
function foo() {
this.bar2 = '默認綁定this指向全局' // 全局變量=> window.bar2
bar = '全局變量'; // 沒有聲明變量 其實是全局變量=>window.bar
}
foo();
複製代碼
當咱們使用默認綁定,this會指向全局,this.something
也會建立一個全局變量,這一點可能不少人沒有注意到。
解決方法:在函數內使用嚴格模式or細心一點
function foo() {
"use strict";
this.bar2 = "嚴格模式下this指向undefined";
bar = "報錯";
}
foo();
複製代碼
固然咱們也能夠手動釋放全局變量的內存:
window.bar = undefined
delete window.bar2
複製代碼
當不須要setInterval
或者setTimeout
時,定時器沒有被clear,定時器的回調函數以及內部依賴的變量都不能被回收,形成內存泄漏。
var someResource = getData();
setInterval(function() {
var node = document.getElementById('Node');
if(node) {
node.innerHTML = JSON.stringify(someResource));
// 定時器也沒有清除
}
// node、someResource 存儲了大量數據 沒法回收
}, 1000);
複製代碼
解決方法: 在定時器完成工做的時候,手動清除定時器。
閉包能夠維持函數內局部變量,使其得不到釋放,形成內存泄漏。
function bindEvent() {
var obj = document.createElement("XXX");
var unused = function () {
console.log(obj,'閉包內引用obj obj不會被釋放');
};
// obj = null;
}
複製代碼
解決方法:手動解除引用,obj = null
。
就是IE9如下的循環引用問題,上文講過了。
var refA = document.getElementById('refA');
document.body.removeChild(refA); // dom刪除了
console.log(refA, "refA"); // 可是還存在引用 能console出整個div 沒有被回收
複製代碼
不信的話,能夠看下這個dom。
解決辦法:refA = null;
過多的console,好比定時器的console會致使瀏覽器卡死。
解決:合理利用console,線上項目儘可能少的使用console,固然若是你要發招聘除外。
記住一個原則:不用的東西,及時歸還,畢竟你是'借的'嘛。
基本類型的值存在內存中,被保存在棧內存中,引用類型的值是對象,保存在堆內存中。因此對象、數組之類的,纔會發生內存泄漏。
瞭解了內存泄漏的緣由以及出現的狀況,那麼咱們在編碼過程當中只要多加註意,就不會發生很是嚴重的內存泄漏問題。
PS:目前離職中,有坑位能夠介紹一下,base:上海2號線淞虹路。
我的blog and 掘金我的主頁,如需轉載,請放上原文連接並署名。碼字不易,感謝支持!
若是喜歡本文的話,歡迎關注個人訂閱號,漫漫技術路,期待將來共同窗習成長。
以上2018.7.7
參考資料:
JS高程4.3垃圾收集