日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

作為 Web 開發(fā)人員,您知道您編寫的每一行代碼都會(huì)對(duì)應(yīng)用程序的性能產(chǎn)生影響嗎?談到 JAVAScript,最需要關(guān)注的領(lǐng)域之一就是內(nèi)存管理。

介紹

作為 Web 開發(fā)人員,您知道您編寫的每一行代碼都會(huì)對(duì)應(yīng)用程序的性能產(chǎn)生影響嗎?談到 JavaScript,最需要關(guān)注的領(lǐng)域之一就是內(nèi)存管理。

想一想,每次用戶與您的網(wǎng)站交互時(shí),他們都會(huì)創(chuàng)建新的對(duì)象、變量和函數(shù)。如果您不小心,這些對(duì)象可能會(huì)堆積起來,阻塞瀏覽器的內(nèi)存并降低整個(gè)用戶體驗(yàn)。這就像信息高速公路上的交通堵塞,一個(gè)令人沮喪的瓶頸,可以讓用戶望而卻步。

但它不一定是這樣的。憑借正確的知識(shí)和技術(shù),您可以控制您的 JavaScript 內(nèi)存并確保您的應(yīng)用程序平穩(wěn)高效地運(yùn)行。

在今天的文章中,我們將探討 JavaScript 內(nèi)存管理的來龍去脈,包括內(nèi)存泄漏的常見原因以及避免它們的策略。無論您是專業(yè)的還是新手JavaScript開發(fā)人員,您都會(huì)對(duì)如何編寫精簡(jiǎn)、平均和快速的代碼有更深入的了解。

了解 JavaScript 內(nèi)存管理

1.垃圾收集器

JavaScript 引擎使用垃圾收集器來釋放不再使用的內(nèi)存。垃圾收集器的工作是識(shí)別并刪除應(yīng)用程序不再使用的對(duì)象。它通過持續(xù)監(jiān)控代碼中的對(duì)象和變量,并跟蹤哪些對(duì)象和變量仍在被引用來實(shí)現(xiàn)這一點(diǎn)。一旦一個(gè)對(duì)象不再被使用,垃圾收集器將其標(biāo)記為刪除并釋放它正在使用的內(nèi)存。

垃圾收集器使用一種稱為“標(biāo)記和清除”的技術(shù)來管理內(nèi)存。它首先標(biāo)記所有仍在使用的對(duì)象,然后“掃過”堆并刪除所有未標(biāo)記的對(duì)象。這個(gè)過程會(huì)定期進(jìn)行,并且在堆內(nèi)存不足時(shí)進(jìn)行,以確保應(yīng)用程序的內(nèi)存使用始終盡可能高效。

2. 堆棧與堆

當(dāng)談到 JavaScript 中的內(nèi)存時(shí),有兩個(gè)主要參與者:堆棧和堆。

堆棧用于存儲(chǔ)僅在函數(shù)執(zhí)行期間需要的數(shù)據(jù)。它快速高效,但容量有限。當(dāng)一個(gè)函數(shù)被調(diào)用時(shí),JavaScript 引擎將函數(shù)的變量和參數(shù)壓入堆棧,當(dāng)函數(shù)返回時(shí),它再次將它們彈出。堆棧用于快速訪問和快速內(nèi)存管理。

另一方面,堆用于存儲(chǔ)應(yīng)用程序整個(gè)生命周期所需的數(shù)據(jù)。它比棧慢一點(diǎn),組織性差一點(diǎn),但容量大得多。堆用于存儲(chǔ)對(duì)象、數(shù)組和其他需要多次訪問的復(fù)雜數(shù)據(jù)結(jié)構(gòu)。

內(nèi)存泄漏的常見原因

您很清楚內(nèi)存泄漏可能是一個(gè)偷偷摸摸的敵人,它會(huì)潛入您的應(yīng)用程序并導(dǎo)致性能問題。通過了解內(nèi)存泄漏的常見原因,您可以用戰(zhàn)勝它們所需的知識(shí)武裝自己。

1. 循環(huán)引用

內(nèi)存泄漏的最常見原因之一是循環(huán)引用。當(dāng)兩個(gè)或多個(gè)對(duì)象相互引用時(shí),就會(huì)發(fā)生這種情況,從而形成垃圾收集器無法破壞的循環(huán)。這可能會(huì)導(dǎo)致對(duì)象在不再需要后很長(zhǎng)時(shí)間內(nèi)仍保留在內(nèi)存中。

這是示例:

 
let object1 = {};
let object2 = {};


// create a circular reference between object1 and object2
object1.next = object2;
object2.prev = object1;


// do something with object1 and object2
// ...


// set object1 and object2 to null to break the circular reference
object1 = null;
object2 = null;

在此示例中,我們創(chuàng)建了兩個(gè)對(duì)象,object1 和 object2,并通過向它們添加 next 和 prev 屬性在它們之間創(chuàng)建循環(huán)引用。

然后,我們將 object1 和 object2 設(shè)置為 null 以打破循環(huán)引用,但由于垃圾收集器無法打破循環(huán)引用,因此對(duì)象將在不再需要后很長(zhǎng)時(shí)間內(nèi)保留在內(nèi)存中,從而導(dǎo)致內(nèi)存泄漏。

為了避免這種類型的內(nèi)存泄漏,我們可以使用一種稱為“手動(dòng)內(nèi)存管理”的技術(shù),通過使用 JavaScript 的 delete 關(guān)鍵字來刪除創(chuàng)建循環(huán)引用的屬性。

 
delete object1.next;
delete object2.prev;

避免此類內(nèi)存泄漏的另一種方法是使用 WeakMap 和 WeakSet,它們?cè)试S您創(chuàng)建對(duì)對(duì)象和變量的弱引用,您可以在本文后面閱讀有關(guān)此選項(xiàng)的更多信息。

2.事件監(jiān)聽器

內(nèi)存泄漏的另一個(gè)常見原因是事件監(jiān)聽器,當(dāng)您將事件偵聽器附加到元素時(shí),它會(huì)創(chuàng)建對(duì)偵聽器函數(shù)的引用,該函數(shù)可以防止垃圾收集器釋放元素使用的內(nèi)存。如果在不再需要該元素時(shí)未刪除偵聽器函數(shù),這可能會(huì)導(dǎo)致內(nèi)存泄漏。

我們一起來看一個(gè)例子:

 
let button = document.getElementById("my-button");


// attach an event listener to the button
button.addEventListener("click", function() {
  console.log("Button was clicked!");
});


// do something with the button
// ...


// remove the button from the DOM
button.parentNode.removeChild(button);

在此示例中,我們將事件偵聽器附加到按鈕元素,然后從 DOM 中刪除該按鈕。即使按鈕元素不再存在于文檔中,事件偵聽器仍附加到它,這會(huì)創(chuàng)建對(duì)偵聽器函數(shù)的引用,以防止垃圾收集器釋放該元素使用的內(nèi)存。如果在不再需要該元素時(shí)未刪除偵聽器函數(shù),這可能會(huì)導(dǎo)致內(nèi)存泄漏。

為避免此類內(nèi)存泄漏,在不再需要該元素時(shí)刪除事件偵聽器很重要:

 
button.removeEventListener("click", function() {
  console.log("Button was clicked!");
});

另一種方法是使用 EventTarget.removeAllListeners() 方法刪除所有已添加到特定事件目標(biāo)的事件偵聽器。

 
button.removeAllListeners();

3.全局變量

內(nèi)存泄漏的第三個(gè)常見原因是全局變量。當(dāng)您創(chuàng)建全局變量時(shí),可以從代碼中的任何位置訪問它,這使得很難確定何時(shí)不再需要它。這可能會(huì)導(dǎo)致變量在不再需要后很長(zhǎng)時(shí)間仍保留在內(nèi)存中。這是一個(gè)例子:

 
// create a global variable
let myData = {
  largeArray: new Array(1000000).fill("some data"),
  id: 1
};


// do something with myData
// ...


// set myData to null to break the reference
myData = null;

在這個(gè)例子中,我們創(chuàng)建了一個(gè)全局變量 myData 并在其中存儲(chǔ)了大量數(shù)據(jù)。

然后我們將 myData 設(shè)置為 null 以中斷引用,但是由于該變量是全局變量,它仍然可以從您的代碼中的任何位置訪問,并且很難確定何時(shí)不再需要它,這會(huì)導(dǎo)致該變量在內(nèi)存中保留很長(zhǎng)時(shí)間 在不再需要它之后,導(dǎo)致內(nèi)存泄漏。

為避免這種類型的內(nèi)存泄漏,您可以使用“函數(shù)作用域”技術(shù)。它涉及創(chuàng)建一個(gè)函數(shù)并在該函數(shù)內(nèi)聲明變量,以便它們只能在函數(shù)范圍內(nèi)訪問。這樣,當(dāng)不再需要該函數(shù)時(shí),變量會(huì)自動(dòng)被垃圾回收。

 
function myFunction() {
  let myData = {
    largeArray: new Array(1000000).fill("some data"),
    id: 1
  };


  // do something with myData
  // ...
}
myFunction();

另一種方法是使用 JavaScript 的 let 和 const 代替 var,這允許您創(chuàng)建塊范圍的變量。用 let 和 const 聲明的變量只能在定義它們的塊內(nèi)訪問,并且當(dāng)它們超出范圍時(shí)將被自動(dòng)垃圾收集。

 
{
  let myData = {
    largeArray: new Array(1000000).fill("some data"),
    id: 1
  };


  // do something with myData
  // ...
}

手動(dòng)內(nèi)存管理的最佳實(shí)踐

JavaScript 提供了內(nèi)存管理工具和技術(shù),可以幫助您控制應(yīng)用程序的內(nèi)存使用情況。

1.使用弱引用

JavaScript 中最強(qiáng)大的內(nèi)存管理工具之一是 WeakMap 和 WeakSet。這些是特殊的數(shù)據(jù)結(jié)構(gòu),允許您創(chuàng)建對(duì)對(duì)象和變量的弱引用。

弱引用不同于常規(guī)引用,因?yàn)樗鼈儾粫?huì)阻止垃圾收集器釋放對(duì)象使用的內(nèi)存。這使它們成為避免循環(huán)引用引起的內(nèi)存泄漏的好工具。這是一個(gè)例子:

 
let object1 = {};
let object2 = {};


// create a WeakMap
let weakMap = new WeakMap();


// create a circular reference by adding object1 to the WeakMap
// and then adding the WeakMap to object1
weakMap.set(object1, "some data");
object1.weakMap = weakMap;


// create a WeakSet and add object2 to it
let weakSet = new WeakSet();
weakSet.add(object2);


// in this case, the garbage collector will be able to free up the memory
// used by object1 and object2, since the references to them are weak

在這個(gè)例子中,我們創(chuàng)建了兩個(gè)對(duì)象,object1 和 object2,并通過將它們分別添加到 WeakMap 和 WeakSet 來創(chuàng)建它們之間的循環(huán)引用。

因?yàn)閷?duì)這些對(duì)象的引用很弱,垃圾收集器將能夠釋放它們使用的內(nèi)存,即使它們?nèi)栽诒灰谩_@有助于防止循環(huán)引用引起的內(nèi)存泄漏。

2. 使用垃圾收集器 API

另一種內(nèi)存管理技術(shù)是使用垃圾收集器 API,它允許您手動(dòng)觸發(fā)垃圾收集并獲取有關(guān)堆當(dāng)前狀態(tài)的信息。

這對(duì)于調(diào)試內(nèi)存泄漏和性能問題很有用。

以下是一個(gè)例子:

 
let object1 = {};
let object2 = {};


// create a circular reference between object1 and object2
object1.next = object2;
object2.prev = object1;


// manually trigger garbage collection
gc();

在此示例中,我們創(chuàng)建了兩個(gè)對(duì)象,object1 和 object2,并通過向它們添加 next 和 prev 屬性在它們之間創(chuàng)建循環(huán)引用。然后,我們使用 gc() 函數(shù)手動(dòng)觸發(fā)垃圾收集,這將釋放對(duì)象使用的內(nèi)存,即使它們?nèi)栽诒灰谩?/p>

請(qǐng)務(wù)必注意,并非所有 JavaScript 引擎都支持 gc() 函數(shù),其行為也可能因引擎而異。還需要注意的是,手動(dòng)觸發(fā)垃圾回收會(huì)對(duì)性能產(chǎn)生影響,因此,建議謹(jǐn)慎使用,僅在必要時(shí)使用。

除了 gc() 函數(shù),JavaScript 還為一些 JavaScript 引擎提供了 global.gc() 和 global.gc() 函數(shù),也為一些瀏覽器引擎提供了 performance.gc() ,可以用來檢查 堆的當(dāng)前狀態(tài)并測(cè)量垃圾收集過程的性能。

3. 使用堆快照和分析器

JavaScript 還提供堆快照和分析器,可以幫助您了解您的應(yīng)用程序如何使用內(nèi)存。堆快照允許您拍攝堆當(dāng)前狀態(tài)的快照并對(duì)其進(jìn)行分析以查看哪些對(duì)象使用的內(nèi)存最多。

下面是一個(gè)示例,說明如何使用堆快照來識(shí)別應(yīng)用程序中的內(nèi)存泄漏:

 
// Start a heap snapshot
let snapshot1 = performance.heapSnapshot();


// Do some actions that might cause memory leaks
for (let i = 0; i < 100000; i++) {
  myArray.push({
    largeData: new Array(1000000).fill("some data"), 
    id: i
  });
}


// Take another heap snapshot
let snapshot2 = performance.heapSnapshot();


// Compare the two snapshots to see which objects were created
let diff = snapshot2.compare(snapshot1);


// Analyze the diff to see which objects are using the most memory
diff.forEach(function(item) {
  if (item.size > 1000000) {
    console.log(item.name);
  }
});

在此示例中,我們?cè)趫?zhí)行將大數(shù)據(jù)推送到數(shù)組的循環(huán)之前和之后拍攝兩個(gè)堆快照,然后,比較這兩個(gè)快照以識(shí)別在循環(huán)期間創(chuàng)建的對(duì)象。

接著,我們可以分析差異以查看哪些對(duì)象使用了最多的內(nèi)存,這可以幫助我們識(shí)別由大數(shù)據(jù)引起的內(nèi)存泄漏。

分析器允許您跟蹤應(yīng)用程序的性能并識(shí)別內(nèi)存使用率高的區(qū)域:

 
let profiler = new Profiler();


profiler.start();


// do some actions that might cause memory leaks
for (let i = 0; i < 100000; i++) {
  myArray.push({
    largeData: new Array(1000000).fill("some data"), 
    id: i
  });
}


profiler.stop();


let report = profiler.report();


// analyze the report to identify areas where memory usage is high
for (let func of report) {
  if (func.memory > 1000000) {
    console.log(func.name);
  }
}

在這個(gè)例子中,我們使用 JavaScript 分析器來開始和停止跟蹤我們應(yīng)用程序的性能。該報(bào)告將顯示有關(guān)已調(diào)用函數(shù)的信息以及每個(gè)函數(shù)的內(nèi)存使用情況。

并非所有 JavaScript 引擎和瀏覽器都支持堆快照和分析器,因此在您的應(yīng)用程序中使用它們之前檢查兼容性很重要。

結(jié)論

我們已經(jīng)介紹了 JavaScript 內(nèi)存管理的基礎(chǔ)知識(shí),包括垃圾回收過程、不同類型的內(nèi)存以及 JavaScript 中可用的內(nèi)存管理工具和技術(shù)。我們還討論了內(nèi)存泄漏的常見原因,并提供了如何避免它們的示例。

通過花時(shí)間了解和實(shí)施這些內(nèi)存管理最佳實(shí)踐,您將能夠創(chuàng)建消除內(nèi)存泄漏可能性的應(yīng)用程序。

分享到:
標(biāo)簽:JavaScript
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定