簡(jiǎn)單網(wǎng)站搭建媒介星軟文平臺(tái)
文章目錄
- 函數(shù)提升+上下文
- 函數(shù)釋放
- 拓展-垃圾回收機(jī)制
- 垃圾回收之觸發(fā)應(yīng)用
函數(shù)提升+上下文
-
函數(shù)提升(Hoisting)
- 概念:在JavaScript中,函數(shù)聲明會(huì)被提升到當(dāng)前作用域的頂部。這意味著可以在函數(shù)聲明之前調(diào)用函數(shù)。例如:
sayHello(); function sayHello() {console.log("Hello!"); }
- 原理:當(dāng)JavaScript引擎在執(zhí)行代碼時(shí),會(huì)首先掃描整個(gè)作用域(例如全局作用域或者函數(shù)作用域),找到所有的函數(shù)聲明,并將它們“提升”到作用域的頂部。但需要注意的是,函數(shù)表達(dá)式不會(huì)提升。例如:
// 這會(huì)報(bào)錯(cuò),因?yàn)楹瘮?shù)表達(dá)式不會(huì)提升 sayHi(); var sayHi = function() {console.log("Hi!"); };
- 在上面的代碼中,
var sayHi
這個(gè)變量聲明會(huì)被提升,但是賦值(也就是函數(shù)表達(dá)式部分)不會(huì)提升。所以在調(diào)用sayHi
的時(shí)候,它的值是undefined
,調(diào)用就會(huì)出錯(cuò)。
-
函數(shù)執(zhí)行上下文(Execution Context)
- 概念:執(zhí)行上下文是JavaScript中一個(gè)非常重要的概念,它定義了函數(shù)執(zhí)行時(shí)的環(huán)境。當(dāng)一個(gè)函數(shù)被調(diào)用時(shí),就會(huì)創(chuàng)建一個(gè)新的執(zhí)行上下文。這個(gè)執(zhí)行上下文包括變量對(duì)象(VO)、作用域鏈和
this
的值。 - 創(chuàng)建階段:
- 變量對(duì)象(VO):在執(zhí)行上下文的創(chuàng)建階段,會(huì)創(chuàng)建變量對(duì)象。對(duì)于函數(shù)執(zhí)行上下文,參數(shù)會(huì)作為變量對(duì)象的屬性,函數(shù)內(nèi)部聲明的變量也會(huì)添加到變量對(duì)象中。例如:
在function add(num1, num2) {var result;result = num1 + num2;return result; } add(3, 5);
add
函數(shù)的執(zhí)行上下文中,變量對(duì)象在創(chuàng)建階段會(huì)有num1
、num2
和result
這幾個(gè)屬性,其中num1
和num2
會(huì)被初始化為傳入的參數(shù)值(3和5),result
會(huì)被初始化為undefined
。- 作用域鏈(Scope Chain):作用域鏈?zhǔn)怯僧?dāng)前執(zhí)行上下文的變量對(duì)象和它外層執(zhí)行上下文的變量對(duì)象組成的一個(gè)鏈表。它用于查找變量的值。例如,在一個(gè)嵌套函數(shù)中:
在var globalVar = 10; function outer() {var outerVar = 20;function inner() {var innerVar = 30;console.log(globalVar + outerVar + innerVar);}inner(); } outer();
inner
函數(shù)的執(zhí)行上下文中,作用域鏈?zhǔn)紫葧?huì)查找自己的變量對(duì)象中的innerVar
,然后查找outer
函數(shù)執(zhí)行上下文的變量對(duì)象中的outerVar
,最后查找全局變量對(duì)象中的globalVar
。- this值:
this
的值取決于函數(shù)的調(diào)用方式。在全局環(huán)境中,this
指向window
(在瀏覽器環(huán)境下)。在對(duì)象方法中,this
指向調(diào)用該方法的對(duì)象。例如:
var obj = {name: "John",sayName: function() {console.log(this.name);} }; obj.sayName(); // 輸出 "John"
- 執(zhí)行階段:在執(zhí)行階段,JavaScript引擎會(huì)逐行執(zhí)行函數(shù)中的代碼,對(duì)變量進(jìn)行賦值操作,執(zhí)行函數(shù)調(diào)用等。
- 概念:執(zhí)行上下文是JavaScript中一個(gè)非常重要的概念,它定義了函數(shù)執(zhí)行時(shí)的環(huán)境。當(dāng)一個(gè)函數(shù)被調(diào)用時(shí),就會(huì)創(chuàng)建一個(gè)新的執(zhí)行上下文。這個(gè)執(zhí)行上下文包括變量對(duì)象(VO)、作用域鏈和
-
函數(shù)內(nèi)部使用的對(duì)象
- 函數(shù)參數(shù)作為對(duì)象:函數(shù)可以接收對(duì)象作為參數(shù),然后在函數(shù)內(nèi)部對(duì)這個(gè)對(duì)象進(jìn)行操作。例如:
function updateObject(obj) {obj.property = "new value";return obj; } var myObject = {property: "original value" }; var updatedObject = updateObject(myObject); console.log(updatedObject.property); // 輸出 "new value"
- 在函數(shù)內(nèi)部創(chuàng)建對(duì)象:可以在函數(shù)內(nèi)部使用
new
關(guān)鍵字創(chuàng)建對(duì)象(如果是構(gòu)造函數(shù)的話(huà)),或者使用對(duì)象字面量來(lái)創(chuàng)建對(duì)象。例如:
function createObject() {var newObject = {name: "New Object",description: "This is a newly created object."};return newObject; } var createdObject = createObject(); console.log(createdObject.name); // 輸出 "New Object"
-
監(jiān)聽(tīng)事件清除釋放
- 在DOM中清除事件監(jiān)聽(tīng)器:在瀏覽器環(huán)境下,當(dāng)給DOM元素添加事件監(jiān)聽(tīng)器后,需要在適當(dāng)?shù)臅r(shí)候清除它,以避免內(nèi)存泄漏等問(wèn)題。如果使用
addEventListener
添加事件監(jiān)聽(tīng)器,可以使用removeEventListener
來(lái)清除。例如:
var button = document.getElementById("myButton"); function handleClick() {console.log("Button clicked!"); } button.addEventListener("click", handleClick); // 之后想要清除事件監(jiān)聽(tīng)器 button.removeEventListener("click", handleClick);
- 注意事項(xiàng):在使用
removeEventListener
時(shí),傳遞的函數(shù)必須是和添加監(jiān)聽(tīng)器時(shí)完全相同的函數(shù)引用。如果是使用匿名函數(shù)添加的監(jiān)聽(tīng)器,想要清除就會(huì)比較復(fù)雜。例如,下面這種情況就很難正確地清除監(jiān)聽(tīng)器:
button.addEventListener("click", function() {console.log("Anonymous function click!"); });
- 一種解決方法是將匿名函數(shù)賦值給一個(gè)變量,然后在
removeEventListener
中使用這個(gè)變量:
var anonymousClickHandler = function() {console.log("Anonymous function click!"); }; button.addEventListener("click", anonymousClickHandler); // 清除監(jiān)聽(tīng)器 button.removeEventListener("click", anonymousClickHandler);
- 在DOM中清除事件監(jiān)聽(tīng)器:在瀏覽器環(huán)境下,當(dāng)給DOM元素添加事件監(jiān)聽(tīng)器后,需要在適當(dāng)?shù)臅r(shí)候清除它,以避免內(nèi)存泄漏等問(wèn)題。如果使用
函數(shù)釋放
-
JavaScript的內(nèi)存管理基礎(chǔ)
- 在JavaScript中,內(nèi)存管理主要是由垃圾回收器(Garbage Collector,GC)來(lái)自動(dòng)完成的。垃圾回收器會(huì)定期掃描內(nèi)存,找出那些不再被使用的對(duì)象,并釋放它們所占用的內(nèi)存空間。
- 當(dāng)一個(gè)對(duì)象沒(méi)有任何引用指向它時(shí),就會(huì)被垃圾回收器認(rèn)為是“垃圾”,從而被回收。例如,在下面的代碼中:
function createObject() {let myObject = {name: "Example"};return myObject; } let newObject = createObject(); // 此時(shí)myObject對(duì)象仍然被newObject引用,不會(huì)被回收 newObject = null; // 現(xiàn)在沒(méi)有引用指向myObject對(duì)象了,它會(huì)在下次垃圾回收時(shí)被回收
-
函數(shù)內(nèi)部局部變量的釋放
- 手動(dòng)設(shè)置為
null
:- 在函數(shù)內(nèi)部,如果有一些比較占用內(nèi)存的對(duì)象,如大型數(shù)組、復(fù)雜的對(duì)象等,可以在函數(shù)執(zhí)行結(jié)束前手動(dòng)將它們?cè)O(shè)置為
null
。例如:
function processData() {let largeArray = new Array(1000000).fill(0);// 對(duì)大型數(shù)組進(jìn)行一些操作...// 操作完成后,手動(dòng)將其設(shè)置為nulllargeArray = null; }
- 當(dāng)把
largeArray
設(shè)置為null
后,就切斷了對(duì)這個(gè)大型數(shù)組對(duì)象的引用。這樣,在下一次垃圾回收時(shí),這個(gè)數(shù)組對(duì)象占用的內(nèi)存就有更大的機(jī)會(huì)被回收。不過(guò),需要注意的是,設(shè)置為null
并不意味著立即釋放內(nèi)存,只是告訴垃圾回收器這個(gè)對(duì)象可以被回收了。
- 在函數(shù)內(nèi)部,如果有一些比較占用內(nèi)存的對(duì)象,如大型數(shù)組、復(fù)雜的對(duì)象等,可以在函數(shù)執(zhí)行結(jié)束前手動(dòng)將它們?cè)O(shè)置為
- 讓變量超出作用域:
- 函數(shù)內(nèi)部的局部變量在函數(shù)執(zhí)行結(jié)束后會(huì)自動(dòng)超出作用域。例如:
function limitedScope() {let localVariable = "This is a local variable";console.log(localVariable); } limitedScope(); // 在這里,localVariable已經(jīng)超出了作用域,它所占用的內(nèi)存會(huì)由垃圾回收器來(lái)管理
- 當(dāng)函數(shù)
limitedScope
執(zhí)行完畢后,localVariable
就不再存在于當(dāng)前的執(zhí)行上下文中,它所占用的內(nèi)存會(huì)在適當(dāng)?shù)臅r(shí)候被垃圾回收器回收。但是,如果這個(gè)變量所引用的對(duì)象還被其他地方(如全局變量或者閉包)引用,那么它不會(huì)被回收。
- 手動(dòng)設(shè)置為
-
閉包中的內(nèi)存釋放
- 理解閉包對(duì)內(nèi)存的影響:
- 閉包是指有權(quán)訪(fǎng)問(wèn)另一個(gè)函數(shù)內(nèi)部變量的函數(shù)。當(dāng)一個(gè)函數(shù)返回一個(gè)閉包時(shí),這個(gè)閉包會(huì)保留對(duì)其外部函數(shù)的變量的引用,即使外部函數(shù)已經(jīng)執(zhí)行完畢。例如:
function outerFunction() {let outerVariable = "I'm from outer function";return function innerFunction() {console.log(outerVariable);}; } let closureFunction = outerFunction(); closureFunction(); // 此時(shí),即使outerFunction已經(jīng)執(zhí)行完畢, // outerVariable仍然被closureFunction引用,不會(huì)被回收
- 釋放閉包中的內(nèi)存:
- 要釋放閉包中引用的內(nèi)存,可以通過(guò)將閉包函數(shù)設(shè)置為
null
來(lái)切斷引用。例如:
closureFunction = null; // 現(xiàn)在沒(méi)有引用指向outerVariable了,它會(huì)在下次垃圾回收時(shí)被回收
- 另外,如果閉包中的變量是一個(gè)比較復(fù)雜的對(duì)象,也可以在閉包內(nèi)部手動(dòng)將其設(shè)置為
null
來(lái)幫助垃圾回收。
- 要釋放閉包中引用的內(nèi)存,可以通過(guò)將閉包函數(shù)設(shè)置為
- 理解閉包對(duì)內(nèi)存的影響:
-
處理事件監(jiān)聽(tīng)器和定時(shí)器對(duì)內(nèi)存的影響
- 事件監(jiān)聽(tīng)器:
- 在函數(shù)內(nèi)部添加的事件監(jiān)聽(tīng)器,如果沒(méi)有正確移除,會(huì)導(dǎo)致內(nèi)存泄漏。例如,在一個(gè)函數(shù)中給DOM元素添加了一個(gè)點(diǎn)擊事件監(jiān)聽(tīng)器:
function addEventListenerFunction() {let button = document.getElementById("myButton");button.addEventListener("click", function() {console.log("Button clicked");}); } addEventListenerFunction();
- 每次調(diào)用這個(gè)函數(shù),都會(huì)添加一個(gè)新的點(diǎn)擊事件監(jiān)聽(tīng)器,但是這些監(jiān)聽(tīng)器不會(huì)自動(dòng)被移除。要釋放內(nèi)存,需要在合適的時(shí)候(如組件卸載或者不再需要監(jiān)聽(tīng)事件時(shí))使用
removeEventListener
來(lái)移除事件監(jiān)聽(tīng)器。
- 定時(shí)器:
- 類(lèi)似地,在函數(shù)內(nèi)部設(shè)置的定時(shí)器(如
setTimeout
或setInterval
)也可能會(huì)導(dǎo)致內(nèi)存問(wèn)題。例如:
function setTimerFunction() {let timerId = setTimeout(function() {console.log("Timer expired");}, 1000); } setTimerFunction();
- 要釋放定時(shí)器占用的資源,可以使用
clearTimeout
(對(duì)于setTimeout
)或者clearInterval
(對(duì)于setInterval
)來(lái)取消定時(shí)器。例如:
function cancelTimerFunction() {let timerId = setTimeout(function() {console.log("Timer expired");}, 1000);clearTimeout(timerId); } cancelTimerFunction();
- 類(lèi)似地,在函數(shù)內(nèi)部設(shè)置的定時(shí)器(如
- 事件監(jiān)聽(tīng)器:
拓展-垃圾回收機(jī)制
-
垃圾回收的概念和重要性
- 概念:垃圾回收(Garbage Collection,GC)是一種自動(dòng)內(nèi)存管理機(jī)制,用于回收程序中不再使用的內(nèi)存。在JavaScript等高級(jí)編程語(yǔ)言中,開(kāi)發(fā)人員不需要手動(dòng)分配和釋放內(nèi)存來(lái)存儲(chǔ)對(duì)象和數(shù)據(jù),垃圾回收器會(huì)自動(dòng)處理這些事情。這大大簡(jiǎn)化了編程工作,但也需要開(kāi)發(fā)人員理解其基本原理,以避免潛在的內(nèi)存泄漏等問(wèn)題。
- 重要性:如果沒(méi)有垃圾回收機(jī)制,隨著程序的運(yùn)行,內(nèi)存中會(huì)積累大量不再被使用的對(duì)象,導(dǎo)致內(nèi)存泄漏。內(nèi)存泄漏會(huì)逐漸耗盡系統(tǒng)的內(nèi)存資源,最終可能使程序崩潰或者系統(tǒng)運(yùn)行緩慢。例如,在一個(gè)長(zhǎng)期運(yùn)行的Web應(yīng)用程序中,如果存在內(nèi)存泄漏,用戶(hù)在瀏覽頁(yè)面時(shí)會(huì)發(fā)現(xiàn)頁(yè)面越來(lái)越卡頓,甚至瀏覽器可能會(huì)因?yàn)閮?nèi)存耗盡而無(wú)響應(yīng)。
-
引用計(jì)數(shù)垃圾回收算法
- 原理:
- 引用計(jì)數(shù)算法是一種比較簡(jiǎn)單的垃圾回收算法。它的基本思想是為每個(gè)對(duì)象維護(hù)一個(gè)引用計(jì)數(shù)。當(dāng)一個(gè)對(duì)象被創(chuàng)建并賦值給一個(gè)變量時(shí),它的引用計(jì)數(shù)為1;當(dāng)有新的變量引用這個(gè)對(duì)象時(shí),引用計(jì)數(shù)加1;當(dāng)一個(gè)引用該對(duì)象的變量不再使用(例如,變量被重新賦值或者超出了作用域),引用計(jì)數(shù)減1。當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)為0時(shí),就表示這個(gè)對(duì)象不再被使用,可以被回收。
- 例如,在下面的代碼中:
let a = {name: 'objectA' }; let b = a; // 此時(shí)對(duì)象a的引用計(jì)數(shù)為2 a = null; // 引用計(jì)數(shù)減1,變?yōu)? b = null; // 引用計(jì)數(shù)變?yōu)?,對(duì)象a可以被垃圾回收
- 局限性:
- 循環(huán)引用問(wèn)題是引用計(jì)數(shù)算法的主要缺陷。當(dāng)兩個(gè)或多個(gè)對(duì)象相互引用形成一個(gè)循環(huán)時(shí),它們的引用計(jì)數(shù)永遠(yuǎn)不會(huì)為0,即使這些對(duì)象從程序的其他部分無(wú)法訪(fǎng)問(wèn)。例如:
function createCycle() {let obj1 = {};let obj2 = {};obj1.other = obj2;obj2.other = obj1; } createCycle();
- 在這個(gè)例子中,
obj1
和obj2
相互引用,它們的引用計(jì)數(shù)都為2(自身的引用和對(duì)方的引用)。即使createCycle
函數(shù)執(zhí)行完畢,這兩個(gè)對(duì)象在引用計(jì)數(shù)算法下也不會(huì)被回收,從而導(dǎo)致內(nèi)存泄漏。
- 原理:
-
標(biāo)記 - 清除垃圾回收算法
- 原理:
- 標(biāo)記 - 清除算法是現(xiàn)代JavaScript引擎中常用的垃圾回收算法之一。它的基本過(guò)程包括兩個(gè)階段:標(biāo)記階段和清除階段。
- 在標(biāo)記階段,垃圾回收器從一組被稱(chēng)為“根”(roots)的對(duì)象開(kāi)始,這些根對(duì)象通常包括全局對(duì)象(在瀏覽器環(huán)境中是
window
對(duì)象)、當(dāng)前執(zhí)行棧中的變量等。然后,沿著對(duì)象之間的引用關(guān)系進(jìn)行遍歷,標(biāo)記所有從根對(duì)象可達(dá)的對(duì)象。 - 在清除階段,垃圾回收器遍歷整個(gè)堆內(nèi)存,回收那些沒(méi)有被標(biāo)記的對(duì)象,即將它們所占用的內(nèi)存釋放掉。例如,在一個(gè)簡(jiǎn)單的JavaScript程序中,假設(shè)全局變量
globalObj
引用了一個(gè)對(duì)象,這個(gè)對(duì)象又引用了其他對(duì)象,垃圾回收器會(huì)從globalObj
開(kāi)始標(biāo)記所有可達(dá)的對(duì)象,然后清除那些不可達(dá)的對(duì)象。
- 與引用計(jì)數(shù)算法對(duì)比:
- 標(biāo)記 - 清除算法能夠很好地解決循環(huán)引用的問(wèn)題。在上面的循環(huán)引用示例中,雖然
obj1
和obj2
相互引用,但如果它們無(wú)法從根對(duì)象到達(dá),那么在標(biāo)記 - 清除算法下,它們會(huì)在清除階段被回收。 - 不過(guò),標(biāo)記 - 清除算法也有一些缺點(diǎn)。它在標(biāo)記和清除過(guò)程中需要暫停程序的執(zhí)行(稱(chēng)為“STW”,Stop - The - World),這可能會(huì)導(dǎo)致短暫的性能卡頓。而且,清除后的內(nèi)存空間是不連續(xù)的,可能會(huì)產(chǎn)生內(nèi)存碎片,影響后續(xù)內(nèi)存分配的效率。
- 標(biāo)記 - 清除算法能夠很好地解決循環(huán)引用的問(wèn)題。在上面的循環(huán)引用示例中,雖然
- 原理:
-
標(biāo)記 - 整理垃圾回收算法
- 原理:
- 標(biāo)記 - 整理算法是在標(biāo)記 - 清除算法的基礎(chǔ)上發(fā)展而來(lái)的。它同樣包括標(biāo)記階段,標(biāo)記從根對(duì)象可達(dá)的對(duì)象。在清除階段,它不是簡(jiǎn)單地回收未標(biāo)記的對(duì)象,而是將所有存活的(被標(biāo)記的)對(duì)象向一端移動(dòng),然后將剩余的內(nèi)存空間一次性清理掉。這樣就解決了標(biāo)記 - 清除算法產(chǎn)生內(nèi)存碎片的問(wèn)題。
- 性能考慮:
- 標(biāo)記 - 整理算法雖然解決了內(nèi)存碎片問(wèn)題,但在移動(dòng)對(duì)象的過(guò)程中也需要消耗更多的時(shí)間和資源。因此,不同的JavaScript引擎會(huì)根據(jù)具體的應(yīng)用場(chǎng)景和性能需求,選擇合適的垃圾回收算法或者結(jié)合使用多種算法。例如,V8引擎在新生代(對(duì)象剛創(chuàng)建時(shí)所處的內(nèi)存區(qū)域)主要使用復(fù)制算法(一種特殊的高效的內(nèi)存回收算法,通過(guò)將存活對(duì)象復(fù)制到新的內(nèi)存空間來(lái)實(shí)現(xiàn)回收),在老生代(對(duì)象經(jīng)過(guò)一段時(shí)間后,從新生代晉升到的內(nèi)存區(qū)域)可能會(huì)結(jié)合使用標(biāo)記 - 清除和標(biāo)記 - 整理算法。
- 原理:
-
分代垃圾回收(以V8引擎為例)
- 新生代和老生代的劃分:
- V8引擎將內(nèi)存分為新生代和老生代兩個(gè)區(qū)域。新生代主要用于存儲(chǔ)新創(chuàng)建的對(duì)象,通常這些對(duì)象的生命周期較短。老生代用于存儲(chǔ)經(jīng)過(guò)多次垃圾回收后仍然存活的對(duì)象,這些對(duì)象的生命周期較長(zhǎng)。
- 新生代內(nèi)存空間相對(duì)較小,一般采用更高效的復(fù)制算法進(jìn)行垃圾回收。在復(fù)制算法中,新生代內(nèi)存被劃分為兩個(gè)等大小的區(qū)域,稱(chēng)為From空間和To空間。當(dāng)進(jìn)行垃圾回收時(shí),將From空間中存活的對(duì)象復(fù)制到To空間,然后清空From空間,最后將From空間和To空間的角色互換。
- 對(duì)象晉升:
- 當(dāng)一個(gè)對(duì)象在新生代中經(jīng)過(guò)多次垃圾回收后仍然存活,它會(huì)被晉升到老生代。晉升的條件可能包括對(duì)象的存活時(shí)間達(dá)到一定閾值、對(duì)象的大小超過(guò)一定限制等。老生代的垃圾回收相對(duì)復(fù)雜,因?yàn)槠渲械膶?duì)象數(shù)量較多且生命周期較長(zhǎng),通常會(huì)結(jié)合使用標(biāo)記 - 清除和標(biāo)記 - 整理算法。
- 新生代和老生代的劃分:
垃圾回收之觸發(fā)應(yīng)用
-
垃圾回收器運(yùn)行的情況
- 內(nèi)存達(dá)到一定閾值:
- 不同的JavaScript引擎(如V8引擎等)有自己的內(nèi)存管理策略。當(dāng)內(nèi)存占用達(dá)到一定的閾值時(shí),垃圾回收器就會(huì)自動(dòng)啟動(dòng)。這個(gè)閾值是由JavaScript引擎內(nèi)部設(shè)定的,目的是平衡性能和內(nèi)存使用。例如,在瀏覽器環(huán)境中,V8引擎會(huì)監(jiān)控堆內(nèi)存(用于存儲(chǔ)對(duì)象等數(shù)據(jù))的使用情況。當(dāng)堆內(nèi)存的占用接近其容量上限時(shí),垃圾回收器就會(huì)被觸發(fā),開(kāi)始清理那些不可達(dá)的對(duì)象,釋放內(nèi)存空間。
- 程序空閑時(shí)段:
- 為了盡量減少垃圾回收對(duì)程序性能的影響,JavaScript引擎通常會(huì)選擇在程序相對(duì)空閑的時(shí)段運(yùn)行垃圾回收。比如,當(dāng)事件循環(huán)(Event Loop)中的任務(wù)隊(duì)列暫時(shí)為空,沒(méi)有正在執(zhí)行的JavaScript代碼,且瀏覽器沒(méi)有其他高優(yōu)先級(jí)的任務(wù)(如頁(yè)面渲染)時(shí),垃圾回收器就可能會(huì)啟動(dòng)。這就像是在打掃房間,選擇在房間沒(méi)人活動(dòng)的時(shí)候進(jìn)行打掃,以避免干擾正常的活動(dòng)。
- 全局變量或?qū)ο蟮纳芷诮Y(jié)束(理論情況):
- 在一個(gè)理想的模型中,如果一個(gè)全局變量所引用的對(duì)象不再被需要,且這個(gè)全局變量被重新賦值或者刪除,那么垃圾回收器應(yīng)該回收這個(gè)對(duì)象。例如,在一個(gè)簡(jiǎn)單的腳本中:
let globalObject = {property: 'value' }; // 使用globalObject進(jìn)行一些操作... globalObject = null; // 理論上,此時(shí)這個(gè)對(duì)象應(yīng)該在之后被垃圾回收
- 不過(guò),在實(shí)際情況中,由于JavaScript引擎的復(fù)雜性和各種優(yōu)化策略,即使這樣設(shè)置為
null
,垃圾回收器也不一定會(huì)立即運(yùn)行,而是會(huì)根據(jù)上述提到的內(nèi)存閾值和空閑時(shí)間等因素來(lái)決定何時(shí)運(yùn)行。
- 內(nèi)存達(dá)到一定閾值:
-
無(wú)法主動(dòng)觸發(fā)垃圾回收機(jī)制(在標(biāo)準(zhǔn)JavaScript中):
- 在標(biāo)準(zhǔn)的JavaScript規(guī)范中,沒(méi)有提供直接觸發(fā)垃圾回收的方法。這是因?yàn)槔厥帐且粋€(gè)復(fù)雜的過(guò)程,由JavaScript引擎自動(dòng)管理,目的是確保內(nèi)存的高效利用和程序的性能穩(wěn)定。如果允許隨意觸發(fā)垃圾回收,可能會(huì)導(dǎo)致性能問(wèn)題,例如,頻繁地觸發(fā)垃圾回收可能會(huì)打斷程序的正常執(zhí)行,導(dǎo)致程序卡頓。
- 雖然不能直接觸發(fā),但可以通過(guò)優(yōu)化代碼來(lái)間接地影響垃圾回收的效果。例如,及時(shí)釋放不再使用的對(duì)象引用(如將變量設(shè)置為
null
),避免創(chuàng)建不必要的全局變量,以及正確地管理閉包等,這些做法可以讓垃圾回收器更容易識(shí)別出哪些對(duì)象是不可達(dá)的,從而更高效地回收內(nèi)存。