最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解JavaScript如何避免內(nèi)存泄漏

 更新時(shí)間:2023年10月30日 14:40:36   作者:葡萄城官網(wǎng)  
這篇文章主要為大家詳細(xì)介紹了JavaScript內(nèi)存泄漏的編程模式,并提供一些內(nèi)存管理的改進(jìn)方法,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考一下

前言

過(guò)去,我們?yōu)g覽靜態(tài)網(wǎng)站時(shí)無(wú)須過(guò)多關(guān)注內(nèi)存管理,因?yàn)榧虞d新頁(yè)面時(shí),之前的頁(yè)面信息會(huì)從內(nèi)存中刪除。 然而,隨著單頁(yè)Web應(yīng)用(SPA)的興起,應(yīng)用程序消耗的內(nèi)存越來(lái)越多,這不僅會(huì)降低瀏覽器性能,甚至?xí)?dǎo)致瀏覽器卡死。因此,在編碼實(shí)踐中,開(kāi)發(fā)人員需要更加關(guān)注與內(nèi)存相關(guān)的內(nèi)容。因此,小編今天將為大家介紹JavaScript內(nèi)存泄漏的編程模式,并提供一些內(nèi)存管理的改進(jìn)方法。

什么是內(nèi)存泄漏以及如何發(fā)現(xiàn)它

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

JavaScript對(duì)象被保存在瀏覽器內(nèi)存的堆中,并通過(guò)引用方式訪問(wèn)。值得一提的是,JavaScript垃圾回收器則運(yùn)行于后臺(tái),并通過(guò)識(shí)別無(wú)法訪問(wèn)的對(duì)象來(lái)釋放并恢復(fù)底層存儲(chǔ)空間,從而保證JavaScript引擎的良好運(yùn)行狀態(tài)。

當(dāng)內(nèi)存中的對(duì)象在垃圾回收周期中應(yīng)該被清理時(shí),若它們被另一個(gè)仍然存在于內(nèi)存中的對(duì)象通過(guò)一個(gè)意外的引用所持有,就會(huì)引發(fā)內(nèi)存泄漏問(wèn)題。這種情況下,冗余對(duì)象會(huì)繼續(xù)占據(jù)內(nèi)存空間,導(dǎo)致應(yīng)用程序消耗過(guò)多的內(nèi)存資源,并可能導(dǎo)致性能下降和表現(xiàn)不佳的情況出現(xiàn)。因此,及時(shí)清理無(wú)用對(duì)象并釋放內(nèi)存資源是至關(guān)重要的,以確保應(yīng)用程序的正常運(yùn)行和良好的性能表現(xiàn)。

如何發(fā)現(xiàn)內(nèi)存泄漏

那么如何知道代碼中是否存在內(nèi)存泄漏??jī)?nèi)存泄漏往往隱蔽且很難檢測(cè)和定位。即使代碼中存在內(nèi)存泄漏,瀏覽器在運(yùn)行時(shí)也不會(huì)返回任何錯(cuò)誤。如果注意到頁(yè)面的性能逐漸下降,可以使用瀏覽器內(nèi)置的工具來(lái)確定是否存在內(nèi)存泄漏以及是哪個(gè)對(duì)象引起的。

任務(wù)管理器(不要與操作系統(tǒng)的任務(wù)管理器混淆)提供了瀏覽器中所有選項(xiàng)卡和進(jìn)程的概覽。Chrome 中,可以通過(guò)在 Linux 和 Windows 操作系統(tǒng)上按 Shift+Esc 來(lái)打開(kāi)任務(wù)管理器;而在 Firefox 中,通過(guò)在地址欄中鍵入 about:performance 則可以訪問(wèn)內(nèi)置的管理器,它可以顯示每個(gè)標(biāo)簽的 JavaScript 內(nèi)存占用情況。如果網(wǎng)站停留在那里什么都不做,但 JavaScript內(nèi)存使用量逐漸增加,那很可能是存在內(nèi)存泄漏。

開(kāi)發(fā)者工具提供了一些先進(jìn)的內(nèi)存管理方法,例如,使用Chrome瀏覽器的性能記錄工具,可以對(duì)頁(yè)面的性能進(jìn)行可視化分析。在這個(gè)過(guò)程中,可以通過(guò)一些指標(biāo)來(lái)判斷是否存在內(nèi)存泄漏問(wèn)題,比如堆內(nèi)存使用量增加的情況,并及時(shí)采取措施解決這些問(wèn)題,以確保應(yīng)用程序的正常運(yùn)行和良好的性能表現(xiàn)。

另外,通過(guò)Chrome和Firefox的開(kāi)發(fā)者工具提供的內(nèi)存工具,可以進(jìn)一步探索內(nèi)存使用情況。隊(duì)列內(nèi)存使用快照的比較可以顯示在兩個(gè)快照之間分配了多少內(nèi)存以及分配的位置,并提供額外信息來(lái)幫助識(shí)別代碼中存在問(wèn)題的對(duì)象。這些工具為開(kāi)發(fā)者提供了便利,能夠更好地進(jìn)行內(nèi)存管理和性能優(yōu)化,提高應(yīng)用程序的質(zhì)量和性能。

JavaScript代碼中常見(jiàn)的內(nèi)存泄漏的常見(jiàn)來(lái)源

研究?jī)?nèi)存泄漏問(wèn)題就相當(dāng)于尋找符合垃圾回收機(jī)制的編程方式,有效避免對(duì)象引用的問(wèn)題。下面小編就為大家介紹幾個(gè)常見(jiàn)的容易導(dǎo)致內(nèi)存泄漏的地方:

1.全局變量

全局變量始終存儲(chǔ)在根目錄下,且永遠(yuǎn)不會(huì)被回收。而在JavaScript的開(kāi)發(fā)中,一些錯(cuò)誤會(huì)導(dǎo)致局部變量被轉(zhuǎn)換到了全局,尤其是在非嚴(yán)格的代碼模式下。下面是兩個(gè)常見(jiàn)的局部變量被轉(zhuǎn)化到全局變量的情況:

  • 為未聲明的變量賦值
  • 使用this指向全局對(duì)象。
function createGlobalVariables() {
  leaking1 = 'I leak into the global scope'; // 為未聲明的變量賦值
  this.leaking2 = 'I also leak into the global scope'; // 使用this指向全局對(duì)象
};
createGlobalVariables();
window.leaking1; 
window.leaking2; 

注意:嚴(yán)格模式("use strict")將幫助您避免上面示例中的內(nèi)存泄漏和控制臺(tái)錯(cuò)誤。

2.閉包

函數(shù)中定義的變量會(huì)在函數(shù)退出調(diào)用棧并且在函數(shù)外部沒(méi)有指向它的引用時(shí)被清除。而閉包則會(huì)保持被引用的變量一直存在,即便函數(shù)的執(zhí)行已經(jīng)終止。

function outer() {
  const potentiallyHugeArray = [];

  return function inner() {
    potentiallyHugeArray.push('Hello'); // function inner is closed over the potentiallyHugeArray variable
    console.log('Hello');
  };
};
const sayHello = outer(); // contains definition of the function inner

function repeat(fn, num) {
  for (let i = 0; i < num; i++){
    fn();
  }
}
repeat(sayHello, 10); // each sayHello call pushes another 'Hello' to the potentiallyHugeArray

// now imagine repeat(sayHello, 100000)

在這個(gè)例子中,potentiallyHugeArray從未被任何函數(shù)返回,也無(wú)法被訪問(wèn),但它的大小會(huì)隨著調(diào)用 inner 方法的次數(shù)而增長(zhǎng)。

3.定時(shí)器

在JavaScript中,使用使用 setTimeout 或 setInterval函數(shù)引用對(duì)象是防止對(duì)象被垃圾回收的最常見(jiàn)方法。當(dāng)在代碼中設(shè)置循環(huán)定時(shí)器(可以使 setTimeout 表現(xiàn)得像 setInterval,即使其遞歸)時(shí),只要回調(diào)可調(diào)用,定時(shí)器回調(diào)對(duì)象的引用就會(huì)永遠(yuǎn)保持活動(dòng)狀態(tài)。

例如下面的這段代碼,只有在移除定時(shí)器后,data對(duì)象才會(huì)被垃圾回收。在沒(méi)有移除setInterval之前,它永遠(yuǎn)不會(huì)被刪除,并且data.hugeString 會(huì)一直保留在內(nèi)存中,直到應(yīng)用程序停止。

function setCallback() {
  const data = {
    counter: 0,
    hugeString: new Array(100000).join('x')
  };

  return function cb() {
    data.counter++; // data object is now part of the callback's scope
    console.log(data.counter);
  }
}

setInterval(setCallback(), 1000); // how do we stop it?

那么應(yīng)該如何避免上述這種情況的發(fā)生呢?可以從以下兩個(gè)方法入手:

  • 注意定時(shí)器回調(diào)引用的對(duì)象。
  • 必要時(shí)取消定時(shí)器。

如下方的代碼所示:

function setCallback() {
  // 'unpacking' the data object
  let counter = 0;
  const hugeString = new Array(100000).join('x'); // gets removed when the setCallback returns

  return function cb() {
    counter++; // only counter is part of the callback's scope
    console.log(counter);
  }
}

const timerId = setInterval(setCallback(), 1000); // saving the interval ID

// doing something ...

clearInterval(timerId); // stopping the timer i.e. if button pressed

4.事件監(jiān)聽(tīng)

活動(dòng)的事件監(jiān)聽(tīng)器會(huì)阻止其范圍內(nèi)的所有變量被回收。一旦添加,事件監(jiān)聽(tīng)器會(huì)一直生效,直到下面兩種情況的發(fā)生:

  • 通過(guò) removeEventListener() 移除。
  • 相關(guān)聯(lián)的 DOM 元素被移除。

在下面的示例中,使用匿名內(nèi)聯(lián)函數(shù)作為事件監(jiān)聽(tīng)器,這意味著它不能與 removeEventListener() 一起使用。此外,由于document 不能被移除,觸發(fā)方法中的內(nèi)容會(huì)一直駐留內(nèi)存,即使只使用它觸發(fā)一次。

const hugeString = new Array(100000).join('x');

document.addEventListener('keyup', function() { // anonymous inline function - can't remove it
  doSomething(hugeString); // hugeString is now forever kept in the callback's scope
});

那么如何避免這種情況呢?可以通過(guò)removeEventListener()釋放監(jiān)聽(tīng)器:

function listener() {
  doSomething(hugeString);
}

document.addEventListener('keyup', listener); // named function can be referenced here...
document.removeEventListener('keyup', listener); // ...and here 

如果事件監(jiān)聽(tīng)器只需要運(yùn)行一次,addEventListener() 可以帶有第三個(gè)參數(shù),一個(gè)提供附加選項(xiàng)的對(duì)象。只要將 {once: true} 作為第三個(gè)參數(shù)傳遞給 addEventListener(),監(jiān)聽(tīng)器將在事件處理一次后自動(dòng)刪除。

document.addEventListener('keyup', function listener() {
  doSomething(hugeString);
}, {once: true}); // listener will be removed after running once

5.緩存

如果不斷向緩存中添加內(nèi)容,而未使用的對(duì)象也沒(méi)有移除,也沒(méi)有限制緩存的大小,那么緩存的大小就會(huì)無(wú)限增長(zhǎng):

let user_1 = { name: "Peter", id: 12345 };
let user_2 = { name: "Mark", id: 54321 };
const mapCache = new Map();

function cache(obj){
  if (!mapCache.has(obj)){
    const value = `${obj.name} has an id of ${obj.id}`;
    mapCache.set(obj, value);

    return [value, 'computed'];
  }

  return [mapCache.get(obj), 'cached'];
}

cache(user_1); // ['Peter has an id of 12345', 'computed']
cache(user_1); // ['Peter has an id of 12345', 'cached']
cache(user_2); // ['Mark has an id of 54321', 'computed']

console.log(mapCache); // ((…) => "Peter has an id of 12345", (…) => "Mark has an id of 54321")
user_1 = null; // removing the inactive user

// Garbage Collector
console.log(mapCache); // ((…) => "Peter has an id of 12345", (…) => "Mark has an id of 54321") // first entry is still in cache

為了解決這個(gè)問(wèn)題,需要清除不需要的緩存:

一種有效的解決內(nèi)存泄漏問(wèn)題的方法是使用WeakMap。它是一種數(shù)據(jù)結(jié)構(gòu),其中鍵引用被保持為弱引用,并且僅接受對(duì)象作為鍵。如果使用對(duì)象作為鍵,并且它是唯一引用該對(duì)象的引用,相關(guān)條目將從緩存中移除,并進(jìn)行垃圾回收。在下面的示例中,當(dāng)替換user_1后,與之關(guān)聯(lián)的條目將在下一次垃圾回收時(shí)自動(dòng)從WeakMap中移除。

let user_1 = { name: "Peter", id: 12345 };
let user_2 = { name: "Mark", id: 54321 };
const weakMapCache = new WeakMap();

function cache(obj){
  // ...same as above, but with weakMapCache

  return [weakMapCache.get(obj), 'cached'];
}

cache(user_1); // ['Peter has an id of 12345', 'computed']
cache(user_2); // ['Mark has an id of 54321', 'computed']
console.log(weakMapCache); // ((…) => "Peter has an id of 12345", (…) => "Mark has an id of 54321"}
user_1 = null; // removing the inactive user

// Garbage Collector

console.log(weakMapCache); // ((…) => "Mark has an id of 54321") - first entry gets garbage collected

結(jié)論

對(duì)于復(fù)雜的應(yīng)用程序,檢測(cè)和修復(fù) JavaScript 內(nèi)存泄漏問(wèn)題可能是一項(xiàng)非常艱巨的任務(wù)。了解內(nèi)存泄漏的常見(jiàn)原因以防止它們發(fā)生是非常重要的。在涉及內(nèi)存和性能方面,最重要的是用戶體驗(yàn),這才是最重要的。

到此這篇關(guān)于詳解JavaScript如何避免內(nèi)存泄漏的文章就介紹到這了,更多相關(guān)JavaScript內(nèi)存泄漏內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 通過(guò)javascript獲取iframe里的值示例代碼

    通過(guò)javascript獲取iframe里的值示例代碼

    iframe里的值在實(shí)現(xiàn)一些比較特殊功能時(shí)需要獲取的,下面為大家詳細(xì)介紹下使用javascript獲取iframe里值的方法,感興趣的各位可以參考下哈
    2013-06-06
  • Javascript之面向?qū)ο?-方法

    Javascript之面向?qū)ο?-方法

    本篇文章主要介紹了Javascript的面向?qū)ο?,?duì)對(duì)象方法的調(diào)用、私有方法、靜態(tài)方法、公有方法、特權(quán)方法進(jìn)行了一一介紹,需要的朋友可以看下
    2016-12-12
  • JavaScript中的Promise從入門到精通

    JavaScript中的Promise從入門到精通

    在JavaScript中,Promise是一種用于處理異步操作的對(duì)象,它代表一個(gè)異步操作的最終完成(或失?。┘捌浣Y(jié)果值,本文通過(guò)實(shí)例代碼給大家介紹JavaScript中的Promise從入門到精通,感興趣的朋友跟隨小編一起看看吧
    2025-10-10
  • JavaScript實(shí)現(xiàn)字符串轉(zhuǎn)字符數(shù)組的兩種方式

    JavaScript實(shí)現(xiàn)字符串轉(zhuǎn)字符數(shù)組的兩種方式

    在 JavaScript 的編程世界里,字符串和數(shù)組是極為常見(jiàn)的數(shù)據(jù)類型,在實(shí)際開(kāi)發(fā)中,我們常常會(huì)遇到需要將字符串轉(zhuǎn)換為字符數(shù)組的情況,接下來(lái),我們將深入探討如何使用 JavaScript 實(shí)現(xiàn)這一轉(zhuǎn)換,同時(shí)結(jié)合代碼示例詳細(xì)分析不同方法的特點(diǎn),需要的朋友可以參考下
    2025-04-04
  • JS對(duì)象屬性的檢測(cè)與獲取操作實(shí)例分析

    JS對(duì)象屬性的檢測(cè)與獲取操作實(shí)例分析

    這篇文章主要介紹了JS對(duì)象屬性的檢測(cè)與獲取操作,結(jié)合實(shí)例形式分析了JS針對(duì)ES5、ES6實(shí)現(xiàn)對(duì)象屬性的檢測(cè)與獲取常見(jiàn)操作技巧,需要的朋友可以參考下
    2020-03-03
  • Day.js基礎(chǔ)用法超詳細(xì)舉例講解

    Day.js基礎(chǔ)用法超詳細(xì)舉例講解

    Day.js是一個(gè)極簡(jiǎn)的JavaScript庫(kù),可以為現(xiàn)代瀏覽器解析、驗(yàn)證、操作和顯示日期和時(shí)間,這篇文章主要介紹了Day.js基礎(chǔ)用法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-07-07
  • 微信小程序圖片右邊加兩行文字的代碼

    微信小程序圖片右邊加兩行文字的代碼

    這篇文章主要介紹了微信小程序圖片右邊加兩行文字的代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 利用JS十分鐘判斷數(shù)組中存在元素的多種方式

    利用JS十分鐘判斷數(shù)組中存在元素的多種方式

    這篇文章主要給大家介紹了關(guān)于利用JS十分鐘判斷數(shù)組中存在元素的多種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 自定義滾動(dòng)條3.0

    自定義滾動(dòng)條3.0

    圖片自定義滾動(dòng)條3.0(Duma“自動(dòng)渲染版”,也許世間萬(wàn)物都會(huì)變,但是真摯的愛(ài),卻永遠(yuǎn)留存在心中?。?/div> 2009-07-07
  • 如何利用JS檢查元素是否在視口內(nèi)

    如何利用JS檢查元素是否在視口內(nèi)

    這篇文章主要給大家介紹了關(guān)于如何利用JS檢查元素是否在視口內(nèi)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04

最新評(píng)論

紫金县| 修水县| 遂宁市| 晋中市| 凌云县| 区。| 徐水县| 德庆县| 西和县| 日土县| 离岛区| 大宁县| 根河市| 静宁县| 金塔县| 津市市| 遂川县| 南昌县| 东辽县| 恩平市| 卢湾区| 安义县| 东莞市| 专栏| 容城县| 万年县| 二手房| 石景山区| 花莲市| 靖边县| 方城县| 洛南县| 许昌市| 洛隆县| 福贡县| 蚌埠市| 江油市| 内黄县| 大名县| 武山县| 白山市|