溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript內(nèi)存泄漏的處理方式

發(fā)布時(shí)間:2020-09-11 17:48:14 來(lái)源:腳本之家 閱讀:137 作者:laozhang 欄目:web開(kāi)發(fā)

下面就是小編整理的關(guān)于JS遇到內(nèi)存泄漏問(wèn)題時(shí)應(yīng)該采取的處理方式。

隨著現(xiàn)在的編程語(yǔ)言功能越來(lái)越成熟、復(fù)雜,內(nèi)存管理也容易被大家忽略。本文將會(huì)討論JavaScript中的內(nèi)存泄漏以及如何處理,方便大家在使用JavaScript編碼時(shí),更好的應(yīng)對(duì)內(nèi)存泄漏帶來(lái)的問(wèn)題。

概述

像C語(yǔ)言這樣的編程語(yǔ)言,具有簡(jiǎn)單的內(nèi)存管理功能函數(shù),例如malloc( )和free( )。開(kāi)發(fā)人員可以使用這些功能函數(shù)來(lái)顯式地分配和釋放系統(tǒng)的內(nèi)存。

當(dāng)創(chuàng)建對(duì)象和字符串等時(shí),JavaScript就會(huì)分配內(nèi)存,并在不再使用時(shí)自動(dòng)釋放內(nèi)存,這種機(jī)制被稱為垃圾收集。這種釋放資源看似是“自動(dòng)”的,但本質(zhì)是混淆的,這也給JavaScript(以及其他高級(jí)語(yǔ)言)的開(kāi)發(fā)人員產(chǎn)生了可以不關(guān)心內(nèi)存管理的錯(cuò)誤印象。其實(shí)這是一個(gè)大錯(cuò)誤。

即使使用高級(jí)語(yǔ)言,開(kāi)發(fā)人員也應(yīng)該理解內(nèi)存管理的知識(shí)。有時(shí)自動(dòng)內(nèi)存管理也會(huì)存在問(wèn)題(例如垃圾收集器中的錯(cuò)誤或?qū)嵤┫拗频龋?,開(kāi)發(fā)人員必須了解這些問(wèn)題才能正確地進(jìn)行處理。

內(nèi)存生命周期

無(wú)論你使用的是什么編程語(yǔ)言,內(nèi)存生命周期幾乎都是一樣的:

JavaScript內(nèi)存泄漏的處理方式

以下是對(duì)內(nèi)存生命周期中每個(gè)步驟發(fā)生的情況的概述:

分配內(nèi)存  - 內(nèi)存由操作系統(tǒng)分配,允許程序使用它。在簡(jiǎn)單的編程語(yǔ)言中,這個(gè)過(guò)程是開(kāi)發(fā)人員應(yīng)該處理的一個(gè)顯式操作。然而,在高級(jí)編程語(yǔ)言中,系統(tǒng)會(huì)幫助你完成這個(gè)操作。內(nèi)存使用 -  這是程序使用之前申請(qǐng)內(nèi)存的時(shí)間段,你的代碼會(huì)通過(guò)使用分配的變量

來(lái)對(duì)內(nèi)存進(jìn)行讀取和寫(xiě)入操作。

釋放內(nèi)存  - 對(duì)于不再需要的內(nèi)存進(jìn)行釋放的操作,以便確保其變成空閑狀態(tài)并且可以被再次使用。與分配內(nèi)存操作一樣,這個(gè)操作在簡(jiǎn)單的編程語(yǔ)言中是需要顯示操作的。   什么是內(nèi)存?

在硬件層面上,計(jì)算機(jī)的內(nèi)存由大量的觸發(fā)器組成的。每個(gè)觸發(fā)器包含一些晶體管,并能夠存儲(chǔ)一位數(shù)據(jù)。單獨(dú)的觸發(fā)器可以通過(guò)唯一的標(biāo)識(shí)符來(lái)尋址,所以我們可以讀取和覆蓋它們。因此,從概念上講,我們可以把整個(gè)計(jì)算機(jī)內(nèi)存看作是我們可以讀寫(xiě)的一大塊空間。

很多東西都存儲(chǔ)在內(nèi)存中:

程序使用的所有變量和其他數(shù)據(jù)。程序的代碼,包括操作系統(tǒng)的代碼。

編譯器和操作系統(tǒng)一起工作,來(lái)處理大部分的內(nèi)存管理,但是我們需要了解從本質(zhì)上發(fā)生了什么。

編譯代碼時(shí),編譯器會(huì)檢查原始數(shù)據(jù)類型,并提前計(jì)算它們需要多少內(nèi)存,然后將所需的內(nèi)存分配給調(diào)用堆??臻g中的程序。分配這些變量的空間被稱為堆??臻g,隨著函數(shù)的調(diào)用,內(nèi)存會(huì)被添加到現(xiàn)有的內(nèi)存之上。當(dāng)終止時(shí),空間以LIFO(后進(jìn)先出)順序被移除。例如如下聲明:

int n; // 4個(gè)字節(jié)
int x [4]; // 4個(gè)元素的數(shù)組,每一個(gè)占4個(gè)字節(jié)
double m; // 8個(gè)字節(jié)

編譯器插入與操作系統(tǒng)進(jìn)行交互的代碼,以便在堆棧中請(qǐng)求所需的字節(jié)數(shù)來(lái)存儲(chǔ)變量。

在上面的例子中,編譯器知道每個(gè)變量的確切內(nèi)存地址。實(shí)際上,每當(dāng)我們寫(xiě)入這個(gè)變量n,它就會(huì)在內(nèi)部翻譯成“內(nèi)存地址4127963”。

注意,如果我們?cè)噲D訪問(wèn)x[4],我們將訪問(wèn)與m關(guān)聯(lián)的數(shù)據(jù)。這是因?yàn)槲覀冋谠L問(wèn)數(shù)組中不存在的元素 - 它比數(shù)組中最后一個(gè)數(shù)據(jù)實(shí)際分配的元素多了4個(gè)字節(jié)x[3],并且可能最終讀取(或覆蓋)了一些m比特。這對(duì)其余部分會(huì)產(chǎn)生不利的后果。

JavaScript內(nèi)存泄漏的處理方式

當(dāng)函數(shù)調(diào)用其它函數(shù)時(shí),每個(gè)函數(shù)被調(diào)用時(shí)都會(huì)得到自己的堆棧塊。它會(huì)保留所有的局部變量和一個(gè)程序計(jì)數(shù)器,還會(huì)記錄執(zhí)行的地方。當(dāng)功能完成時(shí),其內(nèi)存塊會(huì)被釋放,可以再次用于其它目的。

動(dòng)態(tài)分配

如若我們不知道編譯時(shí),變量需要的內(nèi)存數(shù)量時(shí),事情就會(huì)變得復(fù)雜。假設(shè)我們想要做如下事項(xiàng):

int n = readInput(); //讀取用戶的輸入
...
//用“n”個(gè)元素創(chuàng)建一個(gè)數(shù)組

在編譯時(shí),編譯器不知道數(shù)組需要多少內(nèi)存,因?yàn)樗怯捎脩籼峁┑妮斎胫禌Q定的。

因此,它不能為堆棧上的變量分配空間。相反,我們的程序需要在運(yùn)行時(shí)明確地向操作系統(tǒng)請(qǐng)求適當(dāng)?shù)目臻g。這個(gè)內(nèi)存是從堆空間分配的。下表總結(jié)了靜態(tài)和動(dòng)態(tài)內(nèi)存分配之間的區(qū)別:

JavaScript內(nèi)存泄漏的處理方式

在JavaScript中分配內(nèi)存

現(xiàn)在來(lái)解釋如何在JavaScript中分配內(nèi)存。

JavaScript使得開(kāi)發(fā)人員免于處理內(nèi)存分配的工作。

var n = 374; // allocates memory for a number
var s = 'sessionstack'; // allocates memory for a string
var o = {
a: 1,
b: null
}; // allocates memory for an object and its contained values
var a = [1, null, 'str']; // (like object) allocates memory for the
// array and its contained values
function f(a) {
return a + 3;
} // allocates a function (which is a callable object)
// function expressions also allocate an object
someElement.addEventListener('click', function() {
someElement.style.backgroundColor = 'blue';
}, false);

一些函數(shù)調(diào)用也會(huì)導(dǎo)致對(duì)象分配:

var d = new Date(); // allocates a Date object
var e = document.createElement('div'); // allocates a DOM element

方法可以分配新的值或?qū)ο螅?/p>

var s1 = 'sessionstack';
var s2 = s1.substr(0, 3); // s2 is a new string
// Since strings are immutable, 
// JavaScript may decide to not allocate memory, 
// but just store the [0, 3] range.
var a1 = ['str1', 'str2'];
var a2 = ['str3', 'str4'];
var a3 = a1.concat(a2); 
// new array with 4 elements being
// the concatenation of a1 and a2 elements

在JavaScript中使用內(nèi)存

基本上在JavaScript中使用分配的內(nèi)存,意味著在其中讀寫(xiě)。

這可以通過(guò)讀取或?qū)懭胱兞炕驅(qū)ο髮傩缘闹?,或者甚至將參?shù)傳遞給函數(shù)來(lái)完成。

當(dāng)內(nèi)存不再需要時(shí)進(jìn)行釋放

大部分內(nèi)存泄漏問(wèn)題都是在這個(gè)階段產(chǎn)生的,這個(gè)階段最難的問(wèn)題就是確定何時(shí)不再需要已分配的內(nèi)存。它通常需要開(kāi)發(fā)人員確定程序中的哪個(gè)部分不再需要這些內(nèi)存,并將其釋放。

高級(jí)語(yǔ)言嵌入了一個(gè)名為垃圾收集器的功能,其工作是跟蹤內(nèi)存分配和使用情況,以便在不再需要分配內(nèi)存的情況下自動(dòng)釋放內(nèi)存。

不幸的是,這個(gè)過(guò)程無(wú)法做到那么準(zhǔn)確,因?yàn)橄衲承﹥?nèi)存不再需要的問(wèn)題是不能由算法來(lái)解決的。

大多數(shù)垃圾收集器通過(guò)收集不能被訪問(wèn)的內(nèi)存來(lái)工作,例如指向它的變量超出范圍的這種情況。然而,這種方式只能收集內(nèi)存空間的近似值,因?yàn)樵趦?nèi)存的某些位置可能仍然有指向它的變量,但它卻不會(huì)被再次訪問(wèn)。

由于確定一些內(nèi)存是否“不再需要”,是不可判定的,所以垃圾收集機(jī)制就有一定的局限性。下面將解釋主要垃圾收集算法及其局限性的概念。

內(nèi)存引用

垃圾收集算法所依賴的主要概念之一就是內(nèi)存引用。

在內(nèi)存管理情況下,如果一個(gè)對(duì)象訪問(wèn)變量(可以是隱含的或顯式的),則稱該對(duì)象引用另一個(gè)對(duì)象。例如,JavaScript對(duì)象具有對(duì)其原對(duì)象(隱式引用)及其屬性值(顯式引用)的引用。

在這種情況下,“對(duì)象”的概念擴(kuò)展到比普通JavaScript對(duì)象更廣泛的范圍,并且還包含函數(shù)范圍。

引用計(jì)數(shù)垃圾收集

這是最簡(jiǎn)單的垃圾收集算法。如果有零個(gè)引用指向它,則該對(duì)象會(huì)被認(rèn)為是“垃圾收集” 。

看看下面的代碼:

var o1 = {
o2: {
x: 1
}
};
// 2 objects are created. 
// 'o2' is referenced by 'o1' object as one of its properties.
// None can be garbage-collected
var o3 = o1; // the 'o3' variable is the second thing that 
// has a reference to the object pointed by 'o1'.
o1 = 1;   // now, the object that was originally in 'o1' has a     
// single reference, embodied by the 'o3' variable
var o4 = o3.o2; // reference to 'o2' property of the object.
// This object has now 2 references: one as
// a property. 
// The other as the 'o4' variable
o3 = '374'; // The object that was originally in 'o1' has now zero
// references to it. 
// It can be garbage-collected.
// However, what was its 'o2' property is still
// referenced by the 'o4' variable, so it cannot be
// freed.
o4 = null; // what was the 'o2' property of the object originally in
// 'o1' has zero references to it. 
// It can be garbage collected.

 

周期引起問(wèn)題

在周期方面有一個(gè)限制。例如下面的例子,創(chuàng)建兩個(gè)對(duì)象并相互引用,這樣會(huì)創(chuàng)建一個(gè)循環(huán)引用。在函數(shù)調(diào)用之后,它們將超出范圍,所以它們實(shí)際上是無(wú)用的,可以被釋放。然而,引用計(jì)數(shù)算法認(rèn)為,由于兩個(gè)對(duì)象中的每一個(gè)都被引用至少一次,所以兩者都不能被垃圾收集機(jī)制收回。

function f() {
var o1 = {};
var o2 = {};
o1.p = o2; // o1 references o2
o2.p = o1; // o2 references o1. This creates a cycle.
}
f( );

JavaScript內(nèi)存泄漏的處理方式

 

標(biāo)記和掃描算法

為了決定是否需要對(duì)象,標(biāo)記和掃描算法會(huì)確定對(duì)象是否是活動(dòng)的。

標(biāo)記和掃描算法經(jīng)過(guò)以下3個(gè)步驟:

roots:通常,root是代碼中引用的全局變量。例如,在JavaScript中,可以充當(dāng)root的全局變量是“窗口”對(duì)象。Node.js中的相同對(duì)象稱為“全局”。所有root的完整列表由垃圾收集器構(gòu)建。然后算法會(huì)檢查所有root和他們的子對(duì)象并且標(biāo)記它們是活動(dòng)的(即它們不是垃圾)。任何root不能達(dá)到的,將被標(biāo)記為垃圾。最后,垃圾回收器釋放所有未標(biāo)記為活動(dòng)的內(nèi)存塊,并將該內(nèi)存返回給操作系統(tǒng)。

JavaScript內(nèi)存泄漏的處理方式

這個(gè)算法比引用計(jì)數(shù)垃圾收集算法更好。JavaScript垃圾收集(代碼/增量/并發(fā)/并行垃圾收集)領(lǐng)域中所做的所有改進(jìn)都是對(duì)這種標(biāo)記和掃描算法的實(shí)現(xiàn)改進(jìn),但不是對(duì)垃圾收集算法本身的改進(jìn)。

周期不再是問(wèn)題了

在上面的相互引用例子中,在函數(shù)調(diào)用返回之后,兩個(gè)對(duì)象不再被全局對(duì)象可訪問(wèn)的對(duì)象引用。因此,它們將被垃圾收集器發(fā)現(xiàn),從而進(jìn)行收回。

JavaScript內(nèi)存泄漏的處理方式

即使在對(duì)象之間有引用,它們也不能從root目錄中訪問(wèn),從而會(huì)被認(rèn)為是垃圾而收集。

抵制垃圾收集器的直觀行為

盡管垃圾收集器使用起來(lái)很方便,但它們也有自己的一套標(biāo)準(zhǔn),其中之一是非決定論。換句話說(shuō),垃圾收集是不可預(yù)測(cè)的。你不能真正知道什么時(shí)候進(jìn)行收集,這意味著在某些情況下,程序會(huì)使用更多的內(nèi)存,雖然這是實(shí)際需要的。在其它情況下,在特別敏感的應(yīng)用程序中,短暫暫停是很可能出現(xiàn)的。盡管非確定性意味著不能確定何時(shí)進(jìn)行集合,但大多數(shù)垃圾收集實(shí)現(xiàn)了共享在分配期間進(jìn)行收集的通用模式。如果沒(méi)有執(zhí)行分配,大多數(shù)垃圾收集會(huì)保持空閑狀態(tài)。如以下情況:

大量的分配被執(zhí)行。大多數(shù)這些元素(或所有這些元素)被標(biāo)記為無(wú)法訪問(wèn)(假設(shè)我們將一個(gè)引用指向不再需要的緩存)。沒(méi)有進(jìn)一步的分配執(zhí)行。

在這種情況下,大多數(shù)垃圾收集不會(huì)做出任何的收集工作。換句話說(shuō),即使有不可用的引用需要收集,但是收集器不會(huì)進(jìn)行收集。雖然這并不是嚴(yán)格的泄漏,但仍會(huì)導(dǎo)致內(nèi)存使用率高于平時(shí)。

什么是內(nèi)存泄漏?

內(nèi)存泄漏是應(yīng)用程序使用過(guò)的內(nèi)存片段,在不再需要時(shí),不能返回到操作系統(tǒng)或可用內(nèi)存池中的情況。

編程語(yǔ)言有各自不同的內(nèi)存管理方式。但是是否使用某一段內(nèi)存,實(shí)際上是一個(gè)不可判定的問(wèn)題。換句話說(shuō),只有開(kāi)發(fā)人員明確的知道是否需要將一塊內(nèi)存返回給操作系統(tǒng)。

四種常見(jiàn)的JavaScript內(nèi)存泄漏

1:全局變量

JavaScript以一種有趣的方式來(lái)處理未聲明的變量:當(dāng)引用未聲明的變量時(shí),會(huì)在全局對(duì)象中創(chuàng)建一個(gè)新變量。在瀏覽器中,全局對(duì)象將是window,這意味著

function foo(arg) {
bar = "some text";
}

相當(dāng)于:

function foo(arg) {
window.bar = "some text";
}

bar只是foo函數(shù)中引用一個(gè)變量。如果你不使用var聲明,將會(huì)創(chuàng)建一個(gè)多余的全局變量。在上述情況下,不會(huì)造成很大的問(wèn)題。但是,如若是下面的這種情況。

你也可能不小心創(chuàng)建一個(gè)全局變量this:

function foo() {
this.var1 = "potential accidental global";
}
// Foo called on its own, this points to the global object (window)
// rather than being undefined.
foo( );

你可以通過(guò)在JavaScript文件的開(kāi)始處添加‘use strict';來(lái)避免這中錯(cuò)誤,這種方式將開(kāi)啟嚴(yán)格的解析JavaScript模式,從而防止意外創(chuàng)建全局變量。

意外的全局變量當(dāng)然是一個(gè)問(wèn)題。更多的時(shí)候,你的代碼會(huì)受到顯式的全局變量的影響,而這些全局變量在垃圾收集器中是無(wú)法收集的。需要特別注意用于臨時(shí)存儲(chǔ)和處理大量信息的全局變量。如果必須使用全局變量來(lái)存儲(chǔ)數(shù)據(jù),那么確保將其分配為空值,或者在完成后重新分配。

 

2:被遺忘的定時(shí)器或回調(diào)

下面列舉setInterval的例子,這也是經(jīng)常在JavaScript中使用。

對(duì)于提供監(jiān)視的庫(kù)和其它接受回調(diào)的工具,通常在確保所有回調(diào)的引用在其實(shí)例無(wú)法訪問(wèn)時(shí),會(huì)變成無(wú)法訪問(wèn)的狀態(tài)。但是下面的代碼卻是一個(gè)例外:

var serverData = loadData();
setInterval(function() {
var renderer = document.getElementById('renderer');
if(renderer) {
renderer.innerHTML = JSON.stringify(serverData);
}
}, 5000); //This will be executed every ~5 seconds.

上面的代碼片段顯示了使用引用節(jié)點(diǎn)或不再需要的數(shù)據(jù)的定時(shí)器的結(jié)果。

該renderer對(duì)象可能會(huì)在某些時(shí)候被替換或刪除,這會(huì)使interval處理程序封裝的塊變得冗余。如果發(fā)生這種情況,那么處理程序及其依賴項(xiàng)都不會(huì)被收集,因?yàn)閕nterval需要先停止。這一切都?xì)w結(jié)為存儲(chǔ)和處理負(fù)載數(shù)據(jù)的serverData不會(huì)被收集的原因。

當(dāng)使用監(jiān)視器時(shí),你需要確保做了一個(gè)明確的調(diào)用來(lái)刪除它們。

幸運(yùn)的是,大多數(shù)現(xiàn)代瀏覽器都會(huì)為你做這件事:即使你忘記刪除監(jiān)聽(tīng)器,當(dāng)被監(jiān)測(cè)對(duì)象變得無(wú)法訪問(wèn),它們就會(huì)自動(dòng)收集監(jiān)測(cè)處理器。這是過(guò)去的一些瀏覽器無(wú)法處理的情況(例如舊的IE6)。

看下面的例子:

var element = document.getElementById('launch-button');
var counter = 0;

function onClick(event) {
counter++;
element.innerHtml = 'text ' + counter;
}
element.addEventListener('click', onClick);
// Do stuff
element.removeEventListener('click', onClick);
element.parentNode.removeChild(element);
// Now when element goes out of scope,
// both element and onClick will be collected even in old browsers // that don't handle cycles well.

由于現(xiàn)代瀏覽器支持垃圾回收機(jī)制,所以當(dāng)某個(gè)節(jié)點(diǎn)變的不能訪問(wèn)時(shí),你不再需要調(diào)用removeEventListener,因?yàn)槔厥諜C(jī)制會(huì)恰當(dāng)?shù)奶幚磉@些節(jié)點(diǎn)。

如果你正在使用jQueryAPI(其他庫(kù)和框架也支持這一點(diǎn)),那么也可以在節(jié)點(diǎn)不用之前刪除監(jiān)聽(tīng)器。即使應(yīng)用程序在較舊的瀏覽器版本下運(yùn)行,庫(kù)也會(huì)確保沒(méi)有內(nèi)存泄漏。

3:閉包

JavaScript開(kāi)發(fā)的一個(gè)關(guān)鍵方面是閉包。閉包是一個(gè)內(nèi)部函數(shù),可以訪問(wèn)外部(封閉)函數(shù)的變量。由于JavaScript運(yùn)行時(shí)的實(shí)現(xiàn)細(xì)節(jié),可能存在以下形式泄漏內(nèi)存:

var theThing = null;
var replaceThing = function(){
var originalThing = theThing; 
var unused = function(){ 
if(originalThing)//對(duì)'originalThing'的引用
console.log(“hi”); 
};
theThing = { 
longStr:new Array(1000000).join('*'),
someMethod:function(){ 
console.log(“message”); 
} 
}; 
};
setInterval(replaceThing,1000);

一旦replaceThing被調(diào)用,theThing會(huì)獲取由一個(gè)大數(shù)組和一個(gè)新的閉包(someMethod)組成的新對(duì)象。然而,originalThing會(huì)被unused變量所持有的閉包所引用(這是theThing從以前的調(diào)用變量replaceThing)。需要記住的是,一旦在同一父作用域中為閉包創(chuàng)建了閉包的作用域,作用域就被共享了。

在這種情況下,閉包創(chuàng)建的范圍會(huì)將someMethod共享給unused。然而,unused有一個(gè)originalThing引用。即使unused從未使用過(guò),someMethod 也可以通過(guò)theThing在整個(gè)范圍之外使用replaceThing。而且someMethod通過(guò)unused共享了閉包范圍,unused必須引用originalThing以便使其它保持活躍(兩封閉之間的整個(gè)共享范圍)。這就阻止了它被收集。

所有這些都可能導(dǎo)致相當(dāng)大的內(nèi)存泄漏。當(dāng)上面的代碼片段一遍又一遍地運(yùn)行時(shí),你會(huì)看到內(nèi)存使用率的不斷上升。當(dāng)垃圾收集器運(yùn)行時(shí),其內(nèi)存大小不會(huì)縮小。這種情況會(huì)創(chuàng)建一個(gè)閉包的鏈表,并且每個(gè)閉包范圍都帶有對(duì)大數(shù)組的間接引用。

 

4:超出DOM引用

在某些情況下,開(kāi)發(fā)人員會(huì)在數(shù)據(jù)結(jié)構(gòu)中存儲(chǔ)DOM節(jié)點(diǎn),例如你想快速更新表格中的幾行內(nèi)容的情況。如果在字典或數(shù)組中存儲(chǔ)對(duì)每個(gè)DOM行的引用,則會(huì)有兩個(gè)對(duì)同一個(gè)DOM元素的引用:一個(gè)在DOM樹(shù)中,另一個(gè)在字典中。如果你不再需要這些行,則需要使兩個(gè)引用都無(wú)法訪問(wèn)。

var elements = {
button: document.getElementById('button'),
image: document.getElementById('image')
};
function doStuff() {
elements.image.src = 'http://example.com/image_name.png';
}
function removeImage() {
// The image is a direct child of the body element.
document.body.removeChild(document.getElementById('image'));
// At this point, we still have a reference to #button in the
//global elements object. In other words, the button element is
//still in memory and cannot be collected by the GC.
}

在涉及DOM樹(shù)內(nèi)的內(nèi)部節(jié)點(diǎn)或葉節(jié)點(diǎn)時(shí),還有一個(gè)額外的因素需要考慮。如果你在代碼中保留對(duì)表格單元格(標(biāo)簽)的引用,并決定從DOM中刪除該表格,還需要保留對(duì)該特定單元格的引用,則可能會(huì)出現(xiàn)嚴(yán)重的內(nèi)存泄漏。你可能會(huì)認(rèn)為垃圾收集器會(huì)釋放除了那個(gè)單元之外的所有東西,但情況并非如此。由于單元格是表格的一個(gè)子節(jié)點(diǎn),并且子節(jié)點(diǎn)保留著對(duì)父節(jié)點(diǎn)的引用,所以對(duì)表格單元格的這種引用,會(huì)將整個(gè)表格保存在內(nèi)存中。

總結(jié)

以上內(nèi)容是對(duì)JavaScript內(nèi)存管理機(jī)制的講解,以及常見(jiàn)的四種內(nèi)存泄漏的分析。希望對(duì)JavaScript的編程人員有所幫助。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI