App下載

js垃圾回收機(jī)制原理給你聊的明明白白

猿友 2020-09-22 10:20:06 瀏覽數(shù) (3131)
反饋

文章來(lái)源于公眾號(hào):前端Symbol盧 ,作者Symbol盧

前言

大多數(shù)語(yǔ)言都是提供自動(dòng)內(nèi)存管理機(jī)制,比如 C#Java ,JavaScript 。自動(dòng)內(nèi)存管理機(jī)制也就是我們經(jīng)常聽(tīng)到的垃圾回收機(jī)制 。好神奇哦,語(yǔ)言會(huì)收垃圾,哈哈,不過(guò)這里的垃圾,可不是家里面的廚余垃圾啥的,而是 一些不再使用的變量所占用的內(nèi)存。我們的 JavaScript 的執(zhí)行環(huán)境會(huì)自動(dòng)對(duì)這些垃圾進(jìn)行回收,也就是釋放那些不再使用的變量所占用的內(nèi)存,收垃圾的過(guò)程 會(huì)按照固定的時(shí)間間隔周期性的執(zhí)行 垃圾回收

內(nèi)存泄露

如果 那些不再使用的變量所占用的內(nèi)存 沒(méi)有被釋放 會(huì)怎樣呢??? 那就會(huì)造成 內(nèi)存泄露

什么是內(nèi)存泄露???別著急往下看

內(nèi)存泄露其實(shí)就是我們的程序中已經(jīng)動(dòng)態(tài)分配的堆內(nèi)存,由于某些原因沒(méi)有得到釋放,造成系統(tǒng)內(nèi)存的浪費(fèi)導(dǎo)致程序運(yùn)行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果。后果很?chē)?yán)重的哦,現(xiàn)在知道為啥要有垃圾回收機(jī)制了嘛

垃圾回收機(jī)制

看看這個(gè)代碼可以加深理解垃圾回收機(jī)制哦?

let name = '編程獅';
function aboutMe() {
  let hobby = '吃肉肉';
  let say=`我是${name},我喜歡${hobby}`;
  console.log(say);
}
aboutMe()

在函數(shù) aboutMe() 執(zhí)行的時(shí)候,聲明了兩個(gè)局部的變量 hobbysay ,等函數(shù)執(zhí)行完畢之后,這兩個(gè)局部變量也就不再使用 ,所以垃圾回收機(jī)制 就會(huì)將不再使用的(局部)變量 hobbysay 清除掉 (釋放了它們的內(nèi)存)

JavaScript 中能實(shí)現(xiàn)這樣的垃圾回收的功能的一共有兩種方式:標(biāo)記清除引用計(jì)數(shù)

標(biāo)記清除

標(biāo)記清除是js中最常用的垃圾回收方式。它的原理也比較好理解,廢話不多說(shuō),先上代碼

function speakLines(){
  let night="天黑";//做個(gè)標(biāo)記 ,進(jìn)入環(huán)境 
  let closeEyes="閉眼";//做個(gè)標(biāo)記 ,進(jìn)入環(huán)境 
  let speak=`開(kāi)始狼人殺,${night}請(qǐng)${closeEyes}`;//做個(gè)標(biāo)記 ,進(jìn)入環(huán)境 
  console.log(speak);
}
speakLines() //代碼執(zhí)行完畢  里面被標(biāo)記過(guò)的變量,又被標(biāo)記 離開(kāi)環(huán)境 最后被回收

當(dāng)代碼執(zhí)行在一個(gè)環(huán)境中時(shí)(例如上面的 speakLines函數(shù)),每聲明一個(gè)變量,就會(huì)對(duì)該變量做一個(gè)標(biāo)記(例如標(biāo)記一個(gè)進(jìn)入執(zhí)行環(huán)境);當(dāng)代碼執(zhí)行進(jìn)入另一個(gè)環(huán)境中時(shí),也就是要離開(kāi)上一個(gè)環(huán)境( speakLines 函數(shù)執(zhí)行完畢,去執(zhí)行其他的函數(shù)),這時(shí)對(duì)上一個(gè)環(huán)境中的變量做一個(gè)標(biāo)記,(例如標(biāo)記一個(gè)離開(kāi)執(zhí)行環(huán)境),等到垃圾回收?qǐng)?zhí)行時(shí),會(huì)根據(jù)標(biāo)記來(lái)決定要清除哪些變量進(jìn)行釋放內(nèi)存

引用計(jì)數(shù)

引用計(jì)數(shù)是一種不太常用的垃圾回收方式。同樣也是先上代碼再說(shuō)原理

let skill = ["唱歌", "彈吉他", "播音"]
function change() {
  let new_skill = ["vue", "react", "node", "webpack", ".net", "mysql", "sqlServer", "nginx"];
  skill = new_skill;
  //一個(gè)文藝小青年就這樣的變成了一個(gè)技術(shù)宅男
}
change()
console.log(skill)  //返回  ["vue", "react", "node", "webpack", ".net", "mysql", "sqlServer", "nginx"]

change()內(nèi)部聲明了一個(gè)局部變量 new_skill,并將一個(gè)引用類(lèi)型 的數(shù)組 賦值給它,同時(shí)又將變量new_skill賦值給了全局變量 skill,此時(shí),這個(gè)局部變量 new_skill 就不會(huì)被當(dāng)成垃圾回收了。啊,為什么呢??? 還記得我們?cè)谏厦嬲f(shuō)過(guò)的 垃圾回收,回收的是那些不再使用的變量,釋放它們的內(nèi)存,因?yàn)榇藭r(shí)的局部變量 new_skill 并不是一個(gè)不再使用 的局部變量了,它被全局變量 skill所引用了( 還在使用),所以就不會(huì)被回收了。

上面的這一過(guò)程,使用的就是引用計(jì)數(shù)的垃圾回收方式

引用計(jì)數(shù)的策略是跟蹤記錄每個(gè)值被使用的次數(shù),當(dāng)聲明了一個(gè)變量并將一個(gè)引用類(lèi)型賦值給該變量的時(shí)候這個(gè)值的引用次數(shù)就加1,如果該變量的值變成了另外一個(gè),則這個(gè)值的引用次數(shù)減1,當(dāng)這個(gè)值的引用次數(shù)變?yōu)?的時(shí)候,說(shuō)明沒(méi)有變量在使用,這個(gè)值沒(méi)法被訪問(wèn)了,因此可以將其占用的空間回收,當(dāng)垃圾回收的時(shí)候,就會(huì)將 引用次數(shù)為0的進(jìn)行回收,釋放對(duì)應(yīng)的內(nèi)存

let skill = ["唱歌", "彈吉他", "播音"]
function change() {
  let new_skill = ["vue", "react", "node", "webpack", ".net", "mysql", "sqlServer", "nginx"];//被引用次數(shù)為0 
  skill = new_skill; ////被引用次數(shù)為1
}
change()
console.log(skill) 

管理內(nèi)存

在我們的項(xiàng)目中,我們肯定是想要用更少的內(nèi)存,來(lái)使得頁(yè)面有更好的性能。這個(gè)時(shí)候就需要我們來(lái)手動(dòng)的管理內(nèi)存了,及時(shí)的去釋放數(shù)據(jù)的引用。我們可以只將需要的數(shù)據(jù),存入變量。一旦這個(gè)數(shù)據(jù)不再使用了,我們需要手動(dòng)的給變量賦值 null 來(lái)釋放數(shù)據(jù)的引用。(解除引用) 大多需要我們進(jìn)行手動(dòng)的解除引用的都是一些全局的變量,因?yàn)榫植康淖兞?,在離開(kāi)環(huán)境的時(shí)候就會(huì)被自動(dòng)清除了。

let skill = ["唱歌", "彈吉他", "播音"]
function change() {
  let new_skill = ["vue", "react", "node", "webpack", ".net", "mysql", "sqlServer", "nginx"]
  skill = new_skill;
  //一個(gè)文藝小青年就這樣的變成了一個(gè)技術(shù)宅男
}
change()
console.log(skill) 
skill = null;//將不再使用的變量進(jìn)行賦值 unll  來(lái)釋放數(shù)據(jù)引用

change() 內(nèi)部聲明的局部變量 new_skill 被全局變量 skill 所引用,所以此時(shí)變量 new_skill 的引用次數(shù)為1,為了讓變量 new_skill 被清除引用,在代碼的最后一行,賦值一個(gè) null 給全局變量 skill,手動(dòng)解除了變量 skill 對(duì)變量 new_skill 的引用,此時(shí)變量 new_skill 的引用次數(shù) 減1,所以 當(dāng)前 new_skill的引用次數(shù)為0了。當(dāng)垃圾回收機(jī)制執(zhí)行的時(shí)候,發(fā)現(xiàn) new_skill 的引用次數(shù)為 0,就把該變量當(dāng)成無(wú)用變量給清除了,釋放了內(nèi)存,提高了性能。

以上就是W3Cschool編程獅關(guān)于js垃圾回收機(jī)制原理給你聊的明明白白的相關(guān)介紹了,希望對(duì)大家有所幫助。

0 人點(diǎn)贊