Javascript 垃圾收集機(jī)制介紹理解
經(jīng)常使用 Javascript 的人會(huì)琢磨其垃圾收集機(jī)制,Javascript 并不像 C,C++ 那樣需要開(kāi)發(fā)者手動(dòng)去清除垃圾,在編寫 Javascript 程序是,開(kāi)發(fā)者無(wú)需關(guān)心內(nèi)存使用問(wèn)題,所需內(nèi)存分配以及無(wú)用內(nèi)存(垃圾)的回收完全實(shí)現(xiàn)了自動(dòng)管理。究其根源,主要是程序收集那些不再使用的變量,并且釋放其占用的內(nèi)存。因此,垃圾收集機(jī)制會(huì)按照固定時(shí)間間隔,周期性反復(fù)的執(zhí)行這一操作。
舉例來(lái)說(shuō),局部變量只存在于函數(shù)內(nèi)部,程序會(huì)為局部變量在棧內(nèi)存或堆內(nèi)存中分配對(duì)應(yīng)的存儲(chǔ)空間,當(dāng)函數(shù)運(yùn)行結(jié)束,局部變量所占用的內(nèi)存就沒(méi)有存在的必要了,這時(shí)程序會(huì)釋放局部變量所占用的內(nèi)存供其他變量使用。這是程序最簡(jiǎn)單釋放內(nèi)存的方法,但是很多時(shí)候,程序中變量會(huì)一直被使用,此時(shí)垃圾收集機(jī)制必須跟蹤變量并且判斷其是否被使用,是否可以釋放其內(nèi)存空間。
垃圾收集機(jī)制主要判斷變量釋放內(nèi)存空間的方法有兩個(gè):其一是標(biāo)記清除法,其二是引用計(jì)數(shù)法。
標(biāo)記法,每個(gè)變量都有其運(yùn)行環(huán)境,變量創(chuàng)建后會(huì)在某種環(huán)境中運(yùn)行,比如創(chuàng)建一個(gè)局部變量,局部變量會(huì)運(yùn)行在函數(shù)體內(nèi)。當(dāng)函數(shù)運(yùn)行時(shí),會(huì)標(biāo)記局部變量為“進(jìn)入環(huán)境”,當(dāng)函數(shù)體運(yùn)行結(jié)束后,意味著變量脫離了其運(yùn)行環(huán)境,此時(shí)則將變量標(biāo)記為“離開(kāi)環(huán)境”。對(duì)于“離開(kāi)環(huán)境”的變量,垃圾收集機(jī)制會(huì)進(jìn)行相應(yīng)記錄,并且在下一個(gè)回收周期時(shí)將其釋放。
引用計(jì)數(shù)法,跟蹤記錄每個(gè)值的被引用次數(shù)。聲明一個(gè)變量并將一個(gè)引用類型值賦給該變量時(shí),這個(gè)值得引用次數(shù)就是 1。如果同一個(gè)值又被賦給另外一個(gè)變量,則該值的引用次數(shù)加 1。相反,如果包含對(duì)這個(gè)值的引用的變量又取得另外一個(gè)值,這個(gè)值得引用次數(shù)減 1。當(dāng)這個(gè)值得引用次數(shù)為 0 時(shí),則說(shuō)明沒(méi)有辦法再訪問(wèn)到此值,因此就可以將其占用的內(nèi)存空間回收。當(dāng)垃圾收集器在下一個(gè)周期運(yùn)行時(shí),會(huì)釋放引用次數(shù)為零的值所占用的內(nèi)存空間。(原文解釋參考:Javascript 高級(jí)程序設(shè)計(jì) - 第二版)
舉個(gè)例子來(lái)說(shuō):
function countMethod(){
var object1 = new Object(); // 聲明變量,計(jì)數(shù)器由 0 變?yōu)?1
var object2 = new Object(); // 聲明變量,計(jì)數(shù)器由 0 變?yōu)?1
object1.method1 = object2; // object1 計(jì)數(shù)器 -1,object2 計(jì)數(shù)器 +1
object2.method2 = object1; // object1 計(jì)數(shù)器 +1,object2 計(jì)數(shù)器 -1
}
此函數(shù)運(yùn)行退出后,object1 的計(jì)數(shù)器讀數(shù)為 1,object2 的計(jì)數(shù)器度數(shù)為 1。所以兩個(gè)變量都不會(huì)被銷毀。如果大量的這樣的程序存在于函數(shù)體內(nèi),就會(huì)導(dǎo)致大量的內(nèi)存被浪費(fèi)而無(wú)法回收,從而導(dǎo)致內(nèi)存的泄露。
上述問(wèn)題解決方法,手動(dòng)釋放 object1 object2 所占用的內(nèi)存。即:
object1.method1 = null;
object2.method2 = null;
對(duì)比上面的例子,舉一個(gè)正常情況下的例子。
function countMethod(){
var object1 = new Object(); // 聲明變量,計(jì)數(shù)器由 0 變?yōu)?1
var object2 = new Object(); // 聲明變量,計(jì)數(shù)器由 0 變?yōu)?1
object1.method1 = "This is object1"; // object1 計(jì)數(shù)器 -1,object1 讀數(shù)變?yōu)?
object2.method2 = "This is object2"; // object2 計(jì)數(shù)器 -1,object2 讀數(shù)變?yōu)?
}
通過(guò)上例看出,正常情況下,當(dāng)函數(shù)運(yùn)行結(jié)束后,object1 object2的讀數(shù)均為 0,在下一個(gè)垃圾收集周期時(shí),會(huì)被回收并且釋放其所占用的內(nèi)存。
相關(guān)文章
javascript基礎(chǔ)第一章 JavaScript與用戶端
javascript基礎(chǔ)第一章 JavaScript與用戶端2010-07-07了解JavaScript函數(shù)中的默認(rèn)參數(shù)
JavaScript函數(shù)可以有默認(rèn)參數(shù)值。通過(guò)默認(rèn)函數(shù)參數(shù),你可以初始化帶有默認(rèn)值的正式參數(shù)。下面我們來(lái)一起學(xué)習(xí)一下吧2019-05-05基于JavaScript實(shí)現(xiàn)繼承機(jī)制之構(gòu)造函數(shù)方法對(duì)象冒充的使用詳解
我們知道JavaScript是面向?qū)ο蟮哪_本語(yǔ)言,那么既然是面向?qū)ο螅^承一定是必不可少的了。JavaScript的核心是ECMAScript,JavaScript繼承機(jī)制的實(shí)現(xiàn)其實(shí)就是ECMAScript繼承機(jī)制的實(shí)現(xiàn)2013-05-05javascript模塊化是什么及其優(yōu)缺點(diǎn)介紹
模塊化是一種將系統(tǒng)分離成獨(dú)立功能部分的方法,可將系統(tǒng)分割成獨(dú)立的功能部分,嚴(yán)格定義模塊接口、模塊間具有透明性2013-09-09JavaScript 高級(jí)篇之函數(shù) (四)
本節(jié)我將分享我對(duì)函數(shù),嵌套函數(shù),作為數(shù)據(jù)的函數(shù),作為對(duì)象的函數(shù)等2012-04-04