|
|
|
|
|
什么是JavaScript內(nèi)存泄漏?它是如何產(chǎn)生的?我們該如何避免?在本文中,我將介紹計時器回調(diào)setTimeout()
是如何導(dǎo)致JavaScript內(nèi)存泄漏的,然后示例說明如何避免。
JavaScript中有兩個計時事件,即 setTimeout()
和 setInterval()
。前者在等待指定的毫秒數(shù)后執(zhí)行一個函數(shù),而后者周期性地執(zhí)行一個函數(shù)(每隔一定的時間間隔重復(fù)一次)。
當(dāng)任何對象綁定到計時器回調(diào)時,它不會被釋放,直到超時發(fā)生。在這種情況下,計時器會自行重置并永遠(yuǎn)運(yùn)行,直到超時完成,因?yàn)椴辉试S垃圾收集器刪除內(nèi)存。這些計時器是 javascript 中內(nèi)存泄漏的最常見原因。
例子
在以下示例中,計時器回調(diào)及其綁定對象(tiedObject)將在超時完成之前釋放。與此同時,計時器會自行重置并永遠(yuǎn)運(yùn)行,因此即使沒有對原始對象的引用,它的內(nèi)存空間也永遠(yuǎn)不會被收集。
<html>
<body>
<script>
for (var i = 0; i < 100000; i++) {
var tiedObject = {
callAgain: function() {
var text = this;
var value = setTimeout(function() {
text.callAgain();
}, 100000);
}
}
tiedObject.callAgain();
tiedObject = null;
}
</script>
</body>>
</html>
1、為避免泄漏,在 setInterval()
或 setTimeout()
中提供引用,以便在執(zhí)行垃圾回收之前需要執(zhí)行函數(shù)。
2、一旦不再需要函數(shù),就直接調(diào)用刪除函數(shù)。
下面示例顯示如何避免內(nèi)存泄露
HTML
<p>Live Example</p>
<button onclick="delayedAlert();">Show an alert box after two seconds</button>
<p></p>
<button onclick="clearAlert();">Cancel alert before it happens</button>
JavaScript
var timeoutID;
delayedAlert();
function delayedAlert() {
timeoutID = window.setTimeout(slowAlert, 2000);
}
function slowAlert() {
alert("That was really slow!");
clearAlert();
}
function clearAlert() {
window.clearTimeout(timeoutID);
}
結(jié)果展示
解釋
示例中,在網(wǎng)頁設(shè)置了兩個簡單的按鈕,以觸發(fā) setTimeout()
和 clearTimeout()
方法:按下第一個按鈕會設(shè)置一個定時器,定時器在 2s 后顯示一個警告對話框,并將此次 setTimeout 的定時器 ID 保存起來,按下第二個按鈕可以取消定時器。
返回值timeoutID是一個正整數(shù),表示定時器的編號。這個值可以傳遞給clearTimeout()
來取消該定時器。
需要注意的是 setTimeout()
和 setInterval()
共用一個編號池,技術(shù)上,clearTimeout()
和 clearInterval()
可以互換。但是,為了避免混淆,不要混用取消定時函數(shù)。
在同一個對象上(一個 window 或者 worker),setTimeout()
或者setInterval()
在后續(xù)的調(diào)用不會重用同一個定時器編號。但是不同的對象使用獨(dú)立的編號池。
本文介紹了計時器回調(diào)setTimeout()
是如何導(dǎo)致JavaScript內(nèi)存泄漏的,然后示例說明如何避免。
內(nèi)存泄漏可以定義為應(yīng)用程序不再使用或需要的一塊內(nèi)存,但由于某種原因沒有返回給操作系統(tǒng)。簡單來說,它是永遠(yuǎn)等待使用的被遺忘的數(shù)據(jù)。
參考文章