男女做爽爽爽网站-男女做羞羞高清-男女做爰高清无遮挡免费视频-男女做爰猛烈-男女做爰猛烈吃奶啪啪喷水网站-内射白浆一区

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

JavaScript這幾種內(nèi)存泄露寫法,你要小心了

freeflydom
2025年4月14日 9:55 本文熱度 323

今天我想和你聊聊,前端開發(fā)過程中內(nèi)存泄露的問題。相信你在工作當(dāng)中遇到過這樣的情況,比如,相同的代碼在開發(fā)環(huán)境運(yùn)行得好好的,到線上運(yùn)行一段時(shí)間后就出現(xiàn)頁(yè)面運(yùn)行卡頓,比較嚴(yán)重時(shí),無用的內(nèi)存會(huì)持續(xù)遞增,從而導(dǎo)致整個(gè)系統(tǒng)卡頓,甚至崩潰。那么,這大概率是發(fā)生了內(nèi)存泄漏。

那么,你可以思考幾個(gè)問題:

  • 什么是內(nèi)存泄漏?
  • 為什么會(huì)有內(nèi)存泄漏?
  • 你的哪些寫法可能會(huì)出現(xiàn)內(nèi)存泄漏?

好,帶著這三個(gè)問題,我們來學(xué)習(xí)今天的內(nèi)容。

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

首先什么是內(nèi)存泄漏呢?是放在內(nèi)存中的變量憑空消失了嗎?其實(shí)并不是,而是不再使用的內(nèi)存沒有得到釋放,導(dǎo)致內(nèi)存一直在增加。我打個(gè)簡(jiǎn)單的比方:你跟別人要東西,你不停地要,不停地要,當(dāng)你不需要這些東西的時(shí)候你也不還給別人,這就是內(nèi)存泄漏。

那為什么會(huì)出現(xiàn)內(nèi)存泄漏呢,如果你了解內(nèi)存的生命周期,一定會(huì)知道是哪個(gè)環(huán)節(jié)導(dǎo)致了內(nèi)存泄漏。不管什么程序語(yǔ)言,它的生命周期一般可以按順序分為三個(gè)部分:

我們先來簡(jiǎn)單了解下這三個(gè)部分都做了什么事情:第一部分是內(nèi)存分配,當(dāng)我們創(chuàng)建一個(gè)函數(shù)或者變量時(shí),必須為它分配一定數(shù)量的內(nèi)存;第二部分是內(nèi)存的使用,對(duì)分配的內(nèi)存進(jìn)行讀和寫操作;第三部分是內(nèi)存釋放階段,將不需要的內(nèi)存進(jìn)行釋放。

所有語(yǔ)言的第二部分都是明確的。第一和第三部分在 C 或者 C++ 這類底層語(yǔ)言中是明確的,但在像 JavaScript 這些高級(jí)語(yǔ)言中,大部分都是隱含的。JavaScript 是在創(chuàng)建變量時(shí)自動(dòng)進(jìn)行了分配內(nèi)存,并且在不使用它們時(shí)“自動(dòng)”釋放,釋放的過程稱為垃圾回收。

問題就出現(xiàn)在這個(gè)“自動(dòng)”的垃圾回收,讓前端開發(fā)者錯(cuò)誤地以為他們可以不關(guān)心內(nèi)存管理。但是實(shí)際上瀏覽器 V8 引擎的垃圾回收只能解決一般問題,它自身有一些局限性。

如果你了解標(biāo)記 - 清除垃圾回收算法,就會(huì)知道,它是首先從根開始將可能被引用的對(duì)象用遞歸的方式進(jìn)行標(biāo)記,然后將沒有標(biāo)記到的對(duì)象作為垃圾進(jìn)行回收。

這個(gè)算法假定設(shè)置一個(gè)叫做根的對(duì)象,在 JavaScript 里,根就是是全局對(duì)象 window。垃圾回收器將定期從全局對(duì)象 window 開始,找所有從 window 開始引用的對(duì)象,然后找這些對(duì)象引用的對(duì)象……遞歸完成后,垃圾回收器將找到所有“可獲得”的對(duì)象和收集所有“不能獲得”的對(duì)象,最后將不可獲得的對(duì)象進(jìn)行回收。

但是垃圾回收機(jī)制會(huì)有這樣一個(gè)問題:假如有一些對(duì)象我們已經(jīng)不需要使用了,但是仍然能被訪問到,我們沒有對(duì)它進(jìn)行手動(dòng)清除,那么瀏覽器引擎的就不會(huì)對(duì)這個(gè)對(duì)象回收,當(dāng)無用的對(duì)象越來越多,就會(huì)導(dǎo)致內(nèi)存泄漏。那么哪些寫法會(huì)導(dǎo)致內(nèi)存泄漏呢?我總結(jié)了 JavaScript 中四類常見的內(nèi)存泄漏寫法和避免方法,給你參考。

哪些寫法會(huì)導(dǎo)致內(nèi)存泄漏?

1.未聲明/意外的全局變量

第一種,未聲明或者意外的全局變量。全局變量的生命周期最長(zhǎng),直到頁(yè)面關(guān)閉前,它都存活著,所以全局變量上的內(nèi)存一直都不會(huì)被回收。所以當(dāng)我們寫代碼的時(shí)候如果全局變量使用不當(dāng),沒有及時(shí)回收,或者拼寫錯(cuò)誤將某個(gè)變量掛載到全局變量時(shí),就會(huì)發(fā)生內(nèi)存泄漏了。

var a = '這是一個(gè)全局變量';
function test(){
    b = '變量b'; //b 成為一個(gè)全局變量,不會(huì)被回收
}

這段代碼中,test 函數(shù)中定義了一個(gè)變量 b,沒有使用 var 或者 let 變量進(jìn)行聲明,這時(shí) b 會(huì)成為全局變量,test 執(zhí)行后變量 b 不會(huì)被回收。解決方式也比較簡(jiǎn)單,在 JavaScript 文件中添加'use strict',開啟嚴(yán)格模式,這個(gè)時(shí)候就不能使用 b 這個(gè)意外的全局變量了,開發(fā)時(shí)就會(huì)在瀏覽器控制臺(tái)報(bào)錯(cuò),避免這種情況發(fā)生。

var a = '這是一個(gè)全局變量';
function test(){
    b = '變量b'; //b 成為一個(gè)全局變量,不會(huì)被回收
}

2.遺忘的定時(shí)器

第二類常見的內(nèi)存泄漏是定時(shí)器 setTimeout 和 setInterval,它的生命周期是由瀏覽器專門的線程來維護(hù)的,所以當(dāng)在某個(gè)頁(yè)面使用了定時(shí)器,并且這個(gè)頁(yè)面銷毀時(shí),如果你沒有手動(dòng)去釋放清理這些定時(shí)器,那么這些定時(shí)器還是存活著的。

來看一個(gè)示例,這段代碼通過定時(shí)器注冊(cè)了一個(gè)回調(diào)函數(shù),該回調(diào)函數(shù)內(nèi)又持有當(dāng)前頁(yè)面 ID 為 Node 的 DOM 元素。當(dāng)頁(yè)面銷毀之后,由于定時(shí)器持有該頁(yè)面部分引用而造成定時(shí)器沒有被回收,進(jìn)而導(dǎo)致定時(shí)器內(nèi)部的數(shù)據(jù) someData 也無法被回收,就導(dǎo)致了內(nèi)存泄漏。

var someData = getData();
setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        node.innerHTML = JSON.stringify(someData));
    }
}, 1000);

解決辦法是,在不使用定時(shí)器的時(shí)候?qū)⒍〞r(shí)器取消,setInterval 設(shè)置一個(gè) ID,然后就可以通過 clearInterval(id) 進(jìn)行取消了。

var someData = getData();
var intervalId = setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        node.innerHTML = JSON.stringify(someData));
    }
}, 1000);
// 在不使用的時(shí)候進(jìn)行清除
clearInterval(intervalId)

3.事件綁定

第三種由“事件綁定”導(dǎo)致的內(nèi)存泄漏也非常常見,一般是由于事件響應(yīng)函數(shù)沒有及時(shí)移除,導(dǎo)致重復(fù)綁定或者 DOM 元素已經(jīng)移除后未處理事件響應(yīng)函數(shù)造成的,例如這段 React 代碼:

class Demo extends React.Component {
  componentDidMount() {
    window.addEventListener('resize', function() {
      // do something
    });
  }
  render() {
    return <div>test component</div>;
  }
}

組件在掛載的時(shí)候監(jiān)聽了 resize 事件,但是在組件移除的時(shí)候沒有處理相應(yīng)函數(shù),假如 的掛載和移除非常頻繁,那么就會(huì)在 window 上綁定很多無用的事件監(jiān)聽函數(shù),最終導(dǎo)致內(nèi)存泄漏。

那怎么解決呢?我們可以通過在組件卸載 componentWillUmout 的時(shí)候移除監(jiān)聽事件來避免這個(gè)問題:

class Demo extends React.Component {
  componentDidMount() {
    window.addEventListener('resize', this.handleResize);
  }
  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
  }
  handleResize() {
    // handle resize
  }
  render() {
    return <div>test component</div>;
  }
}

4.閉包

最后一類比較重要,也是我們?cè)陂_發(fā)過程中經(jīng)常使用到的,那就是閉包。這里先聲明:閉包本身沒有錯(cuò),不會(huì)引起內(nèi)存泄漏,而是我們使用錯(cuò)誤導(dǎo)致的。

我們都知道,閉包有兩個(gè)主要作用,一是延伸變量作用域范圍,讀取函數(shù)內(nèi)部的變量。二是讓這些變量的值始終保持在內(nèi)存中。簡(jiǎn)單理解就是,一個(gè)作用域可以訪問另外一個(gè)函數(shù)內(nèi)部的局部變量。

那么,為什么會(huì)說閉包可能會(huì)導(dǎo)致內(nèi)存泄漏呢?函數(shù)本身會(huì)持有它定義時(shí)所在的詞法環(huán)境的引用,但通常情況下,使用完函數(shù)后,該函數(shù)所申請(qǐng)的內(nèi)存都會(huì)被回收了。但當(dāng)函數(shù)內(nèi)再返回一個(gè)函數(shù)時(shí),由于返回的函數(shù)持有外部函數(shù)的詞法環(huán)境,而返回的函數(shù)又被其他生命周期東西所持有,導(dǎo)致外部函數(shù)雖然執(zhí)行完了,但內(nèi)存卻無法被回收。

我們舉個(gè)例子來看一下閉包,這個(gè)例子中函數(shù) f1 里面返回了一個(gè)函數(shù) f2,f2 中使用了 f1 函數(shù)中的變量 n,這樣就形成了閉包。你可以想一下 console.log 的內(nèi)容應(yīng)該是什么?好,答案是在執(zhí)行完 f1 函數(shù)后,第一次調(diào)用 result 結(jié)果返回 1000,第二次調(diào)用結(jié)果返回了 1001。這說明了什么呢?說明變量 n 在函數(shù)執(zhí)行完并沒有被銷毀,而是繼續(xù)留在了內(nèi)存中。

function f1() {
  var n = 999;
  // 一個(gè)閉包
  function f2() {
    n++; // f2 作為內(nèi)部函數(shù),有權(quán)訪問父級(jí)函數(shù)作用域 f1 中的變量
    console.log(n);
  }
  return f2;
}
var result = f1();
result(); // 1000
result(); // 1001

正常來說,閉包并不是內(nèi)存泄漏,因?yàn)檫@種持有外部函數(shù)詞法環(huán)境本就是閉包的特性,就是為了讓這塊內(nèi)存不被回收,因?yàn)榭赡茉谖磥磉€需要用到,但這無疑會(huì)造成內(nèi)存的消耗,所以,我們不應(yīng)該濫用閉包。

總結(jié)

今天的分享到這里就結(jié)束了,最后我們來回顧一下今天講的內(nèi)容。內(nèi)存泄漏發(fā)生在 JavaScript 內(nèi)存自動(dòng)回收階段,瀏覽器引擎在“自動(dòng)”回收階段使用的是標(biāo)記清除算法,可以將“不可獲得”的對(duì)象進(jìn)行回收,如果我們編寫代碼的時(shí)候?qū)σ恍┤肿兞刻幚聿划?dāng),定時(shí)器和事件綁定沒有及時(shí)清除,或者閉包使用不當(dāng),就會(huì)引起內(nèi)存泄漏問題。所以為了避免內(nèi)存泄漏,最重要對(duì)一點(diǎn)就是養(yǎng)成良好對(duì)編程習(xí)慣,比如內(nèi)存分配后,一定要注意寫好內(nèi)存釋放的代碼,有借有還,才能高效運(yùn)轉(zhuǎn),再借不難。

?轉(zhuǎn)自https://juejin.cn/post/7490856819004620836


該文章在 2025/4/14 9:56:00 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 精品国产自在现线免费观看 | 六月丁香在线播放 | 91免费国产韩国电影在线观看 | 亚洲婷婷第一狠人综合精品 | 国产亚洲另类激情第二页 | 一级全黄60分钟免费网站 | 熟女人妻上司中文字幕 | 天美传媒AV成人片免费看 | 国产精品不卡高清在线观看 | 国产成人综合亚洲天堂 | 国产野外一区二区理伦片视频在线 | 制服中文字幕一区二区 | 日韩国产欧美视频在线播放 | 色欲狠狠躁天天躁无码中文字幕 | 丰满人妻av无码一区二区三区 | 国产精品无码一区二区在线A片 | 久久精品国产av麻豆五月丁香 | 国产精品日韩欧美一区二区三区 | 第一区二区快射影院 | 国1国二国三在 | 婷婷在线视频国产综合 | 亚洲日本中文 | 国内精品免费 | 国产欧美成人精品 | 精品人妻无码区二区三区 | 久久99精品波多结衣一区 | 亚洲精品中文字幕不卡在线 | 成人做爰WWW网站视频 | 射精专区一区二区朝鲜小说 | 亚洲综合久久一区二区三区 | 成人性视频欧美一区二区三区 | 国产精品一区AV在线播放 | 丰满老熟女白浆直流 | 国产无码性生活中文字幕 | 亚洲午夜高清 | 成人性生交大片免费看中国A片 | 亚洲成色www久久网站夜月 | 国产精品久久精品 | 黑人两根一起强进 | 亚洲午夜精品A片久久软件 亚洲午夜精品A片一区三区无码 | 麻豆精品在线观看 |