溫馨提示×

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

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

JavaScript如何處理內(nèi)存泄漏

發(fā)布時(shí)間:2020-12-10 09:42:00 來(lái)源:億速云 閱讀:333 作者:小新 欄目:web開(kāi)發(fā)

這篇文章主要介紹了JavaScript如何處理內(nèi)存泄漏,具有一定借鑒價(jià)值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。

概述

像 C 這樣的編程語(yǔ)言,具有低級(jí)內(nèi)存管理原語(yǔ),如malloc()和free()。開(kāi)發(fā)人員使用這些原語(yǔ)顯式地對(duì)操作系統(tǒng)的內(nèi)存進(jìn)行分配和釋放。

而JavaScript在創(chuàng)建對(duì)象(對(duì)象、字符串等)時(shí)會(huì)為它們分配內(nèi)存,不再使用對(duì)時(shí)會(huì)“自動(dòng)”釋放內(nèi)存,這個(gè)過(guò)程稱為垃圾收集。這種看“自動(dòng)”似釋放資源的的特性是造成混亂的根源,因?yàn)檫@給JavaScript(和其他高級(jí)語(yǔ)言)開(kāi)發(fā)人員帶來(lái)一種錯(cuò)覺(jué),以為他們可以不關(guān)心內(nèi)存管理的錯(cuò)誤印象,這是想法一個(gè)大錯(cuò)誤。

即使在使用高級(jí)語(yǔ)言時(shí),開(kāi)發(fā)人員也應(yīng)該了解內(nèi)存管理(或者至少懂得一些基礎(chǔ)知識(shí))。有時(shí)候,自動(dòng)內(nèi)存管理存在一些問(wèn)題(例如垃圾收集器中的bug或?qū)崿F(xiàn)限制等),開(kāi)發(fā)人員必須理解這些問(wèn)題,以便可以正確地處理它們(或者找到一個(gè)適當(dāng)?shù)慕鉀Q方案,以最小代價(jià)來(lái)維護(hù)代碼)。

內(nèi)存的生命周期

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

JavaScript如何處理內(nèi)存泄漏

這里簡(jiǎn)單介紹一下內(nèi)存生命周期中的每一個(gè)階段:

  • 分配內(nèi)存 —? 內(nèi)存是由操作系統(tǒng)分配的,它允許您的程序使用它。在低級(jí)語(yǔ)言(例如C語(yǔ)言)中,這是一個(gè)開(kāi)發(fā)人員需要自己處理的顯式執(zhí)行的操作。然而,在高級(jí)語(yǔ)言中,系統(tǒng)會(huì)自動(dòng)為你分配內(nèi)在。
  • 使用內(nèi)存 — 這是程序?qū)嶋H使用之前分配的內(nèi)存,在代碼中使用分配的變量時(shí),就會(huì)發(fā)生讀和寫(xiě)操作。
  • 釋放內(nèi)存 — 釋放所有不再使用的內(nèi)存,使之成為自由內(nèi)存,并可以被重利用。與分配內(nèi)存操作一樣,這一操作在低級(jí)語(yǔ)言中也是需要顯式地執(zhí)行。

內(nèi)存是什么?

在介紹JavaScript中的內(nèi)存之前,我們將簡(jiǎn)要討論內(nèi)存是什么以及它是如何工作的。

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

作為人類,我們并不擅長(zhǎng)用比特來(lái)思考和計(jì)算,所以我們把它們組織成更大的組,這些組一起可以用來(lái)表示數(shù)字。8位稱為1字節(jié)。除了字節(jié),還有字(有時(shí)是16位,有時(shí)是32位)。

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

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

編譯器和操作系統(tǒng)一起為你處理大部分內(nèi)存管理,但是你還是需要了解一下底層的情況,對(duì)內(nèi)在管理概念會(huì)有更深入的了解。

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

JavaScript如何處理內(nèi)存泄漏

編譯器能夠立即知道所需的內(nèi)存:4 + 4×4 + 8 = 28字節(jié)。

這段代碼展示了整型和雙精度浮點(diǎn)型變量所占內(nèi)存的大小。但是大約20年前,整型變量通常占2個(gè)字節(jié),而雙精度浮點(diǎn)型變量占4個(gè)字節(jié)。你的代碼不應(yīng)該依賴于當(dāng)前基本數(shù)據(jù)類型的大小。

編譯器將插入與操作系統(tǒng)交互的代碼,并申請(qǐng)存儲(chǔ)變量所需的堆棧字節(jié)數(shù)。

在上面的例子中,編譯器知道每個(gè)變量的確切內(nèi)存地址。事實(shí)上,每當(dāng)我們寫(xiě)入變量 n 時(shí),它就會(huì)在內(nèi)部被轉(zhuǎn)換成類似“內(nèi)存地址4127963”這樣的信息。

注意,如果我們嘗試訪問(wèn) x[4],將訪問(wèn)與m關(guān)聯(lián)的數(shù)據(jù)。這是因?yàn)樵L問(wèn)數(shù)組中一個(gè)不存在的元素(它比數(shù)組中最后一個(gè)實(shí)際分配的元素x[3]多4字節(jié)),可能最終讀取(或覆蓋)一些 m 位。這肯定會(huì)對(duì)程序的其余部分產(chǎn)生不可預(yù)知的結(jié)果。

JavaScript如何處理內(nèi)存泄漏

當(dāng)函數(shù)調(diào)用其他函數(shù)時(shí),每個(gè)函數(shù)在調(diào)用堆棧時(shí)獲得自己的塊。它保存所有的局部變量,但也會(huì)有一個(gè)程序計(jì)數(shù)器來(lái)記住它在執(zhí)行過(guò)程中的位置。當(dāng)函數(shù)完成時(shí),它的內(nèi)存塊將再次用于其他地方。

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

不幸的是,當(dāng)編譯時(shí)不知道一個(gè)變量需要多少內(nèi)存時(shí),事情就有點(diǎn)復(fù)雜了。假設(shè)我們想做如下的操作:

JavaScript如何處理內(nèi)存泄漏

在編譯時(shí),編譯器不知道數(shù)組需要使用多少內(nèi)存,因?yàn)檫@是由用戶提供的值決定的。

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

靜態(tài)內(nèi)存分配動(dòng)態(tài)內(nèi)存分配
大小必須在編譯時(shí)知道大小不需要在編譯時(shí)知道
在編譯時(shí)執(zhí)行在運(yùn)行時(shí)執(zhí)行
分配給堆棧分配給堆
FILO (先進(jìn)后出)沒(méi)有特定的分配順序

要完全理解動(dòng)態(tài)內(nèi)存分配是如何工作的,需要在指針上花費(fèi)更多的時(shí)間,這可能與本文的主題有太多的偏離,這里就不太詳細(xì)介紹指針的相關(guān)的知識(shí)了。

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

現(xiàn)在將解釋第一步:如何在JavaScript中分配內(nèi)存。

JavaScript為讓開(kāi)發(fā)人員免于手動(dòng)處理內(nèi)存分配的責(zé)任——JavaScript自己進(jìn)行內(nèi)存分配同時(shí)聲明值。

JavaScript如何處理內(nèi)存泄漏

某些函數(shù)調(diào)用也會(huì)導(dǎo)致對(duì)象的內(nèi)存分配:

JavaScript如何處理內(nèi)存泄漏

方法可以分配新的值或?qū)ο?

JavaScript如何處理內(nèi)存泄漏

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

在JavaScript中使用分配的內(nèi)存意味著在其中讀寫(xiě),這可以通過(guò)讀取或?qū)懭胱兞炕驅(qū)ο髮傩缘闹?,或者將參?shù)傳遞給函數(shù)來(lái)實(shí)現(xiàn)。

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

大多數(shù)的內(nèi)存管理問(wèn)題都出現(xiàn)在這個(gè)階段

這里最困難的地方是確定何時(shí)不再需要分配的內(nèi)存,它通常要求開(kāi)發(fā)人員確定程序中哪些地方不再需要內(nèi)存的并釋放它。

高級(jí)語(yǔ)言嵌入了一種稱為垃圾收集器的機(jī)制,它的工作是跟蹤內(nèi)存分配和使用,以便發(fā)現(xiàn)任何時(shí)候一塊不再需要已分配的內(nèi)在。在這種情況下,它將自動(dòng)釋放這塊內(nèi)存。

不幸的是,這個(gè)過(guò)程只是進(jìn)行粗略估計(jì),因?yàn)楹茈y知道某塊內(nèi)存是否真的需要 (不能通過(guò)算法來(lái)解決)。

大多數(shù)垃圾收集器通過(guò)收集不再被訪問(wèn)的內(nèi)存來(lái)工作,例如,指向它的所有變量都超出了作用域。但是,這是可以收集的內(nèi)存空間集合的一個(gè)不足估計(jì)值,因?yàn)樵趦?nèi)存位置的任何一點(diǎn)上,仍然可能有一個(gè)變量在作用域中指向它,但是它將永遠(yuǎn)不會(huì)被再次訪問(wèn)。

垃圾收集

由于無(wú)法確定某些內(nèi)存是否真的有用,因此,垃圾收集器想了一個(gè)辦法來(lái)解決這個(gè)問(wèn)題。本節(jié)將解釋理解主要垃圾收集算法及其局限性。

內(nèi)存引用

垃圾收集算法主要依賴的是引用。

在內(nèi)存管理上下文中,如果對(duì)象具有對(duì)另一個(gè)對(duì)象的訪問(wèn)權(quán)(可以是隱式的,也可以是顯式的),則稱對(duì)象引用另一個(gè)對(duì)象。例如,JavaScript對(duì)象具有對(duì)其原型(隱式引用)和屬性值(顯式引用)的引用。

在此上下文中,“對(duì)象”的概念被擴(kuò)展到比常規(guī)JavaScript對(duì)象更廣泛的范圍,并且還包含函數(shù)范圍(或全局詞法作用域)。

詞法作用域定義了如何在嵌套函數(shù)中解析變量名:即使父函數(shù)已經(jīng)返回,內(nèi)部函數(shù)也包含父函數(shù)的作用

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

這是最簡(jiǎn)單的垃圾收集算法。如果沒(méi)有指向?qū)ο蟮囊?,則認(rèn)為該對(duì)象是“垃圾可回收的”,如下代碼:

JavaScript如何處理內(nèi)存泄漏

循環(huán)會(huì)產(chǎn)生問(wèn)題

當(dāng)涉及到循環(huán)時(shí),會(huì)有一個(gè)限制。在下面的示例中,創(chuàng)建了兩個(gè)對(duì)象,兩個(gè)對(duì)象互相引用,從而創(chuàng)建了一個(gè)循環(huán)。在函數(shù)調(diào)用之后將超出作用域,因此它們實(shí)際上是無(wú)用的,可以被釋放。然而,引用計(jì)數(shù)算法認(rèn)為,由于每個(gè)對(duì)象至少被引用一次,所以它們都不能被垃圾收集。

JavaScript如何處理內(nèi)存泄漏

標(biāo)記-清除(Mark-and-sweep)算法

該算法能夠判斷出某個(gè)對(duì)象是否可以訪問(wèn),從而知道該對(duì)象是否有用,該算法由以下步驟組成:

  1. 垃圾收集器構(gòu)建一個(gè)“根”列表,用于保存引用的全局變量。在JavaScript中,“window”對(duì)象是一個(gè)可作為根節(jié)點(diǎn)的全局變量。
  2. 然后,算法檢查所有根及其子節(jié)點(diǎn),并將它們標(biāo)記為活動(dòng)的(這意味著它們不是垃圾)。任何根不能到達(dá)的地方都將被標(biāo)記為垃圾。
  3. 最后,垃圾收集器釋放所有未標(biāo)記為活動(dòng)的內(nèi)存塊,并將該內(nèi)存返回給操作系統(tǒng)。

JavaScript如何處理內(nèi)存泄漏

這個(gè)算法比上一個(gè)算法要好,因?yàn)椤耙粋€(gè)對(duì)象沒(méi)有被引用”就意味著這個(gè)對(duì)象無(wú)法訪問(wèn)。

截至2012年,所有現(xiàn)代瀏覽器都有標(biāo)記-清除垃圾收集器。過(guò)去幾年在JavaScript垃圾收集(分代/增量/并發(fā)/并行垃圾收集)領(lǐng)域所做的所有改進(jìn)都是對(duì)該算法(標(biāo)記-清除)的實(shí)現(xiàn)改進(jìn),而不是對(duì)垃圾收集算法本身的改進(jìn),也不是它決定對(duì)象是否可訪問(wèn)的目標(biāo)。

在這篇文章中,你可以更詳細(xì)地閱讀到有關(guān)跟蹤垃圾收集的詳細(xì)信息,同時(shí)還包括了標(biāo)記-清除算法及其優(yōu)化。

循環(huán)不再是問(wèn)題

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

JavaScript如何處理內(nèi)存泄漏

盡管對(duì)象之間存在引用,但它們對(duì)于根節(jié)點(diǎn)來(lái)說(shuō)是不可達(dá)的。

垃圾收集器的反直觀行為

盡管垃圾收集器很方便,但它們有一套自己的折衷方案,其中之一就是非決定論,換句話說(shuō),GC是不可預(yù)測(cè)的,你無(wú)法真正判斷何時(shí)進(jìn)行垃圾收集。這意味著在某些情況下,程序會(huì)使用更多的內(nèi)存,這實(shí)際上是必需的。在對(duì)速度特別敏感的應(yīng)用程序中,可能會(huì)很明顯的感受到短時(shí)間的停頓。如果沒(méi)有分配內(nèi)存,則大多數(shù)GC將處于空閑狀態(tài)。看看以下場(chǎng)景:

  1. 分配一組相當(dāng)大的內(nèi)在。
  2. 這些元素中的大多數(shù)(或全部)被標(biāo)記為不可訪問(wèn)(假設(shè)引用指向一個(gè)不再需要的緩存)。
  3. 不再進(jìn)一步的分配

在這些場(chǎng)景中,大多數(shù)GCs 將不再繼續(xù)收集。換句話說(shuō),即使有不可訪問(wèn)的引用可供收集,收集器也不會(huì)聲明這些引用。這些并不是嚴(yán)格意義上的泄漏,但仍然會(huì)導(dǎo)致比通常更高的內(nèi)存使用。

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

從本質(zhì)上說(shuō),內(nèi)存泄漏可以定義為:不再被應(yīng)用程序所需要的內(nèi)存,出于某種原因,它不會(huì)返回到操作系統(tǒng)或空閑內(nèi)存池中。

JavaScript如何處理內(nèi)存泄漏

編程語(yǔ)言支持不同的內(nèi)存管理方式。然而,是否使用某一塊內(nèi)存實(shí)際上是一個(gè)無(wú)法確定的問(wèn)題。換句話說(shuō),只有開(kāi)發(fā)人員才能明確一塊內(nèi)存是否可以返回到操作系統(tǒng)。

某些編程語(yǔ)言為開(kāi)發(fā)人員提供了幫助,另一些則期望開(kāi)發(fā)人員能清楚地了解內(nèi)存何時(shí)不再被使用。維基百科上有一些有關(guān)人工和自動(dòng)內(nèi)存管理的很不錯(cuò)的文章。

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

1.全局變量

JavaScript以一種有趣的方式處理未聲明的變量: 對(duì)于未聲明的變量,會(huì)在全局范圍中創(chuàng)建一個(gè)新的變量來(lái)對(duì)其進(jìn)行引用。在瀏覽器中,全局對(duì)象是window。例如:

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

等價(jià)于:

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

如果bar在foo函數(shù)的作用域內(nèi)對(duì)一個(gè)變量進(jìn)行引用,卻忘記使用var來(lái)聲明它,那么將創(chuàng)建一個(gè)意想不到的全局變量。在這個(gè)例子中,遺漏一個(gè)簡(jiǎn)單的字符串不會(huì)造成太大的危害,但這肯定會(huì)很糟。

創(chuàng)建一個(gè)意料之外的全局變量的另一種方法是使用this:

function foo() {
    this.var1 = "potential accidental global";
}
// Foo自己調(diào)用,它指向全局對(duì)象(window),而不是未定義。
foo();
可以在JavaScript文件的開(kāi)頭通過(guò)添加“use strict”來(lái)避免這一切,它將開(kāi)啟一個(gè)更嚴(yán)格的JavaScript解析模式,以防止意外創(chuàng)建全局變量。

盡管我們討論的是未知的全局變量,但仍然有很多代碼充斥著顯式的全局變量。根據(jù)定義,這些是不可收集的(除非被指定為空或重新分配)。用于臨時(shí)存儲(chǔ)和處理大量信息的全局變量特別令人擔(dān)憂。如果你必須使用一個(gè)全局變量來(lái)存儲(chǔ)大量數(shù)據(jù),那么請(qǐng)確保將其指定為null,或者在完成后將其重新賦值。

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

setInterval為例,因?yàn)樗贘avaScript中經(jīng)常使用。

var serverData = loadData();
setInterval(function() {
    var renderer = document.getElementById('renderer');
    if(renderer) {
        renderer.innerHTML = JSON.stringify(serverData);
    }
}, 5000); //每五秒會(huì)執(zhí)行一次

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

renderer表示的對(duì)象可能會(huì)在未來(lái)的某個(gè)時(shí)間點(diǎn)被刪除,從而導(dǎo)致內(nèi)部處理程序中的一整塊代碼都變得不再需要。但是,由于定時(shí)器仍然是活動(dòng)的,所以,處理程序不能被收集,并且其依賴項(xiàng)也無(wú)法被收集。這意味著,存儲(chǔ)著大量數(shù)據(jù)的serverData也不能被收集。

在使用觀察者時(shí),您需要確保在使用完它們之后進(jìn)行顯式調(diào)用來(lái)刪除它們(要么不再需要觀察者,要么對(duì)象將變得不可訪問(wèn))。

作為開(kāi)發(fā)者時(shí),需要確保在完成它們之后進(jìn)行顯式刪除它們(或者對(duì)象將無(wú)法訪問(wèn))。

在過(guò)去,一些瀏覽器無(wú)法處理這些情況(很好的IE6)。幸運(yùn)的是,現(xiàn)在大多數(shù)現(xiàn)代瀏覽器會(huì)為幫你完成這項(xiàng)工作:一旦觀察到的對(duì)象變得不可訪問(wèn),即使忘記刪除偵聽(tīng)器,它們也會(huì)自動(dòng)收集觀察者處理程序。然而,我們還是應(yīng)該在對(duì)象被處理之前顯式地刪除這些觀察者。例如:

JavaScript如何處理內(nèi)存泄漏

如今,現(xiàn)在的瀏覽器(包括IE和Edge)使用現(xiàn)代的垃圾回收算法,可以立即發(fā)現(xiàn)并處理這些循環(huán)引用。換句話說(shuō),在一個(gè)節(jié)點(diǎn)刪除之前也不是必須要調(diào)用removeEventListener。

一些框架或庫(kù),比如JQuery,會(huì)在處置節(jié)點(diǎn)之前自動(dòng)刪除監(jiān)聽(tīng)器(在使用它們特定的API的時(shí)候)。這是由庫(kù)內(nèi)部的機(jī)制實(shí)現(xiàn)的,能夠確保不發(fā)生內(nèi)存泄漏,即使在有問(wèn)題的瀏覽器下運(yùn)行也能這樣,比如……IE 6。

3.閉包

閉包是javascript開(kāi)發(fā)的一個(gè)關(guān)鍵方面,一個(gè)內(nèi)部函數(shù)使用了外部(封閉)函數(shù)的變量。由于JavaScript運(yùn)行的細(xì)節(jié),它可能以下面的方式造成內(nèi)存泄漏:

JavaScript如何處理內(nèi)存泄漏

這段代碼做了一件事:每次調(diào)用replaceThing的時(shí)候,theThing都會(huì)得到一個(gè)包含一個(gè)大數(shù)組和一個(gè)新閉包(someMethod)的新對(duì)象。同時(shí),變量unused指向一個(gè)引用了`originalThing的閉包。

是不是有點(diǎn)困惑了? 重要的是,一旦具有相同父作用域的多個(gè)閉包的作用域被創(chuàng)建,則這個(gè)作用域就可以被共享。

在這種情況下,為閉包someMethod而創(chuàng)建的作用域可以被unused共享的。unused內(nèi)部存在一個(gè)對(duì)originalThing的引用。即使unused從未使用過(guò),someMethod也可以在replaceThing的作用域之外(例如在全局范圍內(nèi))通過(guò)theThing來(lái)被調(diào)用。

由于someMethod共享了unused閉包的作用域,那么unused引用包含的originalThing會(huì)迫使它保持活動(dòng)狀態(tài)(兩個(gè)閉包之間的整個(gè)共享作用域)。這阻止了它被收集。

當(dāng)這段代碼重復(fù)運(yùn)行時(shí),可以觀察到內(nèi)存使用在穩(wěn)定增長(zhǎng),當(dāng)GC運(yùn)行后,內(nèi)存使用也不會(huì)變小。從本質(zhì)上說(shuō),在運(yùn)行過(guò)程中創(chuàng)建了一個(gè)閉包鏈表(它的根是以變量theThing的形式存在),并且每個(gè)閉包的作用域都間接引用了了一個(gè)大數(shù)組,這造成了相當(dāng)大的內(nèi)存泄漏。

4.脫離DOM的引用

有時(shí),將DOM節(jié)點(diǎn)存儲(chǔ)在數(shù)據(jù)結(jié)構(gòu)中可能會(huì)很有用。假設(shè)你希望快速地更新表中的幾行內(nèi)容,那么你可以在一個(gè)字典或數(shù)組中保存每個(gè)DOM行的引用。這樣,同一個(gè)DOM元素就存在兩個(gè)引用:一個(gè)在DOM樹(shù)中,另一個(gè)則在字典中。如果在將來(lái)的某個(gè)時(shí)候你決定刪除這些行,那么你需要將這兩個(gè)引用都設(shè)置為不可訪問(wèn)。

在引用 DOM 樹(shù)中的內(nèi)部節(jié)點(diǎn)或葉節(jié)點(diǎn)時(shí),還需要考慮另外一個(gè)問(wèn)題。如果在代碼中保留對(duì)表單元格的引用(<td>標(biāo)記),并決定從 DOM 中刪除表,同時(shí)保留對(duì)該特定單元格的引用,那么可能會(huì)出現(xiàn)內(nèi)存泄漏。

你可能認(rèn)為垃圾收集器將釋放除該單元格之外的所有內(nèi)容。然而,事實(shí)并非如此,由于單元格是表的一個(gè)子節(jié)點(diǎn),而子節(jié)點(diǎn)保存對(duì)父節(jié)點(diǎn)的引用,所以對(duì)表單元格的這個(gè)引用將使整個(gè)表保持在內(nèi)存中,所以在移除有被引用的節(jié)點(diǎn)時(shí)候要移除其子節(jié)點(diǎn)。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享JavaScript如何處理內(nèi)存泄漏內(nèi)容對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,遇到問(wèn)題就找億速云,詳細(xì)的解決方法等著你來(lái)學(xué)習(xí)!

向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