瀏覽器的垃圾回收機制
在 JS 中創建一個變量的時候,系統會根據,變量的類型,自動為其分配對應的內存(基礎類型 -> 棧內存,固定大小;對象類型 -> 堆內存,根據需要分配大小)。
正常情況下,當這些變量不再被使用的時候,就會被回收,內存被釋放。
瀏覽器的垃圾回收機制及原理
內存泄漏?
官方解釋:內存泄漏(Memory Leak)是指程序中己動態分配的堆內存由於某種原因程序未釋放或無法釋放,造成系統內存的浪費,導致程序運行速度減慢甚至系統崩潰等嚴重后果。
通俗點就是指由於疏忽或者錯誤造成程序未能釋放已經不再使用的內存,不再用到的內存卻沒有及時釋放,從而造成內存上的浪費。
造成內存泄漏的幾種情況:
1. 定義全局變量
在局部作用域中,等函數執行完畢,變量就沒有存在的必要了,垃圾回收機制很虧地做出判斷並且回收,但是對於全局變量,很難判斷什么時候不用這些變量,無法正常回收;所以,盡量少使用全局變量。
意外的全局變量:
function foo() {
a = 'test'
}
// 上面的寫法等價於
function foo() {
window.a = 'test'
}
function foo() {
this.a = 'test'
// 函數自身發生調用,this指向全局對象window
}
foo();
上面的a變量應該是foo()內部作用域變量的引用,由於沒有使用var來聲明這個變量,這時變量a就被創建成了全局變量,這個就是錯誤的,會導致內存泄漏。
解決方式:使用 var let const 來定義變量。或者在js文件開頭添加 ‘use strict',開啟嚴格模式。
- 閉包(函數套函數,子函數引用了父函數的參數或變,並且被外部引用,形成不被釋放的作用域,稱之閉包)
在使用閉包的時候,就會造成嚴重的內存泄漏,因為閉包中的局部變量,會一直保存在內存中。
// 閉包維持了 onclick 方法的內部變量,並且這個綁定在了 DOM 上。
function bindEvent() {
var obj = document.querySelector("#xxx");
obj.onclick = function () { };
};
// 解決方案1
function bindEvent() {
var obj = document.querySelector("#xxx");
obj.onclick = onClickHandler;
};
function onClickHandler () {};
// 解決方案2
function bindEvent() {
var obj = document.querySelector("#xxx");
obj.onclick = function () { };
obj.onclick = null;
}
-
定時器
定時器setInterval或者setTimeout在不需要使用的時候,沒有被clear,導致定時器的回調函數及其內部依賴的變量都不能被回收,這就會造成內存泄漏。
解決方式:當不需要interval或者timeout的時候,調用clearInterval或者clearTimeout -
事件監聽
DOM.addEventListener("click", callback)
垃圾回收機制不好判斷該事件是否需要被解除,導致 callback 不能被釋放,此時需要手動解除綁定:DOM.removeEventListener(callback)
-
元素引用沒有清理
var a = document.getElementById('id');
document.body.removeChild(a);
// 不能回收,因為存在變量a對它的引用。雖然我們用removeChild移除了,但是還在對象里保存着#的引用,即DOM元素還在內存里面。
解決方法: a = null;
- console
控制台日志記錄對總體內存內置文件的影響,也是個重大的問題,同時也是容易被忽略的。記錄錯誤的對象,可以將大量的數據保留在內存中。
傳遞給console.log的對象是不能被垃圾回收,所以沒有去掉console.log可能會存在內存泄漏