深入解讀JavaScript內(nèi)存回收機(jī)制
JavaScript語(yǔ)言是一門優(yōu)秀的腳本語(yǔ)言.其中包含腳本語(yǔ)言的靈活性外還擁有許多高級(jí)語(yǔ)言的特性.例如充許構(gòu)建和實(shí)例化一個(gè)對(duì)象,垃圾回收機(jī)制(GC:Garbage Collecation).通常我們使用new創(chuàng)建對(duì)象,GC負(fù)責(zé)回收對(duì)象占用內(nèi)存區(qū)域.因此了解GC,可以加深對(duì)JavaScript垃圾回收機(jī)制的理解。
1.用局部變量和全局變量解釋GC
GC在回收內(nèi)存時(shí),首先會(huì)判斷該對(duì)象是否被其它對(duì)象引用.在確定沒有其它對(duì)象引用便釋放該對(duì)象內(nèi)存區(qū)域.因此如何確定對(duì)象不再被引用是GC的關(guān)鍵所在.
- <script>
- function aa(){
- this.rr = "彈窗";
- }
- function bb(){
- this.rr = "彈窗";
- }
- var b1;
- function cc(){
- var a1 = new aa();
- b1 = new bb();
- return b1;
- }
- cc();
- alert(b1.rr)
- </script>
如上代碼中,執(zhí)行完cc()后a1被回收了,此后我們可以通過b1.rr彈出文字窗口.在一些基礎(chǔ)書籍中解釋為:a1為局部變量,b1是全局變量.局部變量執(zhí)行完后會(huì)被GC回收.但不全是這樣,如下代碼:
- <script>
- function aa(){
- this.rr = "彈窗";
- }
- function bb(){
- this.rr = "彈窗";
- }
- function cc(){
- var a1 = new aa();
- var b1 = new bb();
- return b1;
- }
- var b1 = cc();
- alert(b1.rr);
- </script>
此時(shí)cc函數(shù)中的 a1,b1都是局部變量,但仍然會(huì)彈出文字窗口.說明b1并沒有被GC回收.因此JavaScript中局部變量不是所有時(shí)候都被GC回收的.
2.抽象理解GC
GC回收機(jī)制還需要近一步了解。在此時(shí)引入幾個(gè)概念:雙向鏈表,作用域鏈,活動(dòng)對(duì)象(為了方便理解,簡(jiǎn)化了原文的概念
Javascript閉包(closure) 深入淺出 , 其中雙向鏈表描述復(fù)雜對(duì)象的上下層級(jí)關(guān)系. 作用域鏈與活動(dòng)對(duì)象分別是雙向鏈表中的某個(gè)節(jié)點(diǎn).以函數(shù)cc為例變量層級(jí)關(guān)系為:
- window<=>cc<=>a1<=>rr
- <=>b1<=>rr
(原文有詳細(xì)解釋)在執(zhí)行cc()方法時(shí),內(nèi)存中變量的引用關(guān)系如上圖,文字解釋如下:
window的活動(dòng)對(duì)象包括cc,假設(shè)window是***對(duì)象(因?yàn)檫\(yùn)行中不會(huì)被回收)
- cc的活動(dòng)對(duì)象包括a1和b1,其作用域鏈?zhǔn)莣indow
- a1的活動(dòng)對(duì)象包括rr,其作用域鏈?zhǔn)莄c
- b1的活動(dòng)對(duì)象包括rr,其作用域鏈?zhǔn)莄c
執(zhí)行cc()時(shí),cc的執(zhí)行環(huán)境會(huì)創(chuàng)建一個(gè)活動(dòng)對(duì)象和一個(gè)作用域鏈.其局部變量a1,b1都會(huì)掛在cc的活動(dòng)對(duì)象中.當(dāng)cc()執(zhí)行完畢后,執(zhí)行環(huán)境會(huì)嘗試回收活動(dòng)對(duì)象占用的內(nèi)存.但因局部變量b1 通過return b1,為其增加了一條作用域鏈:window<=>b1<=>rr,所以GC停止對(duì)b1回收.
因此如果想將一個(gè)局部變量/函數(shù)提升為全局的,為其增加一條作用域鏈就OK了。
同時(shí)控制好對(duì)象的作用域鏈也變得重要了.因作用域鏈會(huì)意外導(dǎo)致GC無法回收目標(biāo)對(duì)象.例如:
- <SCRIPT LANGUAGE="JavaScript">
- <!--
- //貓
- function cat(name){
- var zhuren ;
- this.name = name;
- //設(shè)置主人
- this.addZhuRen = function(zr){
- zhuren = zr;
- }
- this.getZhuRen = function(){
- return zhuren;
- }
- }
- //主人
- function zhuren(name){
- this.name = name;
- }
- //創(chuàng)建主人:
- var zr = new zhuren("zhangsan");
- //創(chuàng)建貓
- var cat1 = new cat("asan");
- //設(shè)置該貓的主人
- cat1.addZhuRen(zr);
- //釋放主人
- zr = null ;
- //此處還存在對(duì)主人對(duì)象的引用
- alert(cat1.getZhuRen().name)
- //-->
- </SCRIPT>
原文鏈接 :http://www.cnblogs.com/a_bu/archive/2011/01/16/1936549.html
【編輯推薦】