垃圾回收
- 程序是運(yùn)行在內(nèi)存里的,當(dāng)聲明一個變量、定義一個函數(shù)時都會占用內(nèi)存,當(dāng)變量或函數(shù)不再使用時,就把所分配的內(nèi)存空間釋放出來,就叫做垃圾回收,它是一種自動的內(nèi)存管理機(jī)制
垃圾回收的兩種策略:標(biāo)記清除 和 引用計(jì)數(shù)
引用計(jì)數(shù)
- 如果這個對象不再被引用,就會被回收
let obj1 = { A: 1 }; // A 的引用個數(shù)為 1
let obj2 = obj1; // A 的引用個數(shù)變?yōu)?2
obj1 = 0; // A 的引用個數(shù)變?yōu)?1
obj2 = 0; // A 的引用個數(shù)變?yōu)?0,此時對象 A 就可以被回收
標(biāo)記清除
- 在變量進(jìn)入執(zhí)行環(huán)境時,會添加一個進(jìn)入標(biāo)記,當(dāng)變量離開時,會添加一個離開標(biāo)記,標(biāo)記清除是GC在運(yùn)行時會給所有變量加上標(biāo)記,然后去掉那些還在環(huán)境中或還被環(huán)境中變量引用的變量,清除剩下還被標(biāo)記的所有變量
- 可能導(dǎo)致的問題是,清除后,內(nèi)容空間不連續(xù),產(chǎn)生了內(nèi)存碎片,可以用標(biāo)記整理來解決
常見的幾種情況
- 引用計(jì)數(shù)中的循環(huán)引用
function func() {
let obj1 = {};
let obj2 = {};
obj1.a = obj2; // obj1 引用 obj2
obj2.a = obj1; // obj2 引用 obj1
}
//函數(shù)結(jié)束后,obj1,obj2的引用都不為0,因此不會被回收,這時需要手動將它們賦為null
obj1.a = null; obj2.a = null;
- 在清空數(shù)組的時候,可以給
array.length=0 -
DOM操作的時候,比如:li是ul的子元素,與父元素是引用關(guān)系,如果保存了li的引用,則ul會一直在內(nèi)存中
const button = document.getElementById('button');
document.body.removeChild(document.getElementById('button'));
雖然刪除了按鈕,但是button的引用還一直在內(nèi)存中,需要手動將button=null
總結(jié)
- 可能導(dǎo)致內(nèi)存泄漏的一定是引用類型的變量,比如函數(shù)和其他自定義對象。值類型的變量是不存在內(nèi)存泄漏的,比如字符串、數(shù)字、布爾值等,因?yàn)橹殿愋褪强繌?fù)制來傳遞,而引用類型是靠指針來傳遞
- 減少內(nèi)存垃圾的一個方法就是避免創(chuàng)建對象,創(chuàng)建對象的方式有
new Object(); const obj = {};
內(nèi)存泄漏
- 我們已經(jīng)無法再引用某個對象時,但垃圾回收器卻認(rèn)為這個對象還在被引用,因此在回收的時候不會釋放它