垃圾回收:JavaScript代碼運行時,需要分配內(nèi)存空間來儲存變量和值。當變量不在參與運行時,就需要系統(tǒng)收回被占用的內(nèi)存空間,這就是垃圾回收。
回收機制:Javascript 具有自動垃圾回收機制,會定期對那些不再使用的變量、對象所占用的內(nèi)存進行釋放,原理就是找到不再使用的變量,然后釋放掉其占用的內(nèi)存。
JavaScript中存在兩種變量:局部變量和全局變量。全局變量的生命周期會持續(xù)要頁面卸載;而局部變量聲明在函數(shù)中,它的生命周期從函數(shù)執(zhí)行開始,直到函數(shù)執(zhí)行結(jié)束,在這個過程中,局部變量會在堆或棧中存儲它們的值,當函數(shù)執(zhí)行結(jié)束后,這些局部變量不再被使用,它們所占有的空間就會被釋放。
不過,當局部變量被外部函數(shù)使用時,其中一種情況就是閉包,在函數(shù)執(zhí)行結(jié)束后,函數(shù)外部的變量依然指向函數(shù)內(nèi)部的局部變量,此時局部變量依然在被使用,所以不會回收。
(2)垃圾回收的方式
瀏覽器通常使用的垃圾回收方法有兩種:標記清除,引用計數(shù)。
1)標記清除
標記清除是瀏覽器常見的垃圾回收方式,當變量進入執(zhí)行環(huán)境時,就標記這個變量“進入環(huán)境”,被標記為“進入環(huán)境”的變量是不能被回收的,因為他們正在被使用。當變量離開環(huán)境時,就會被標記為“離開環(huán)境”,被標記為“離開環(huán)境”的變量會被內(nèi)存釋放。
垃圾收集器在運行的時候會給存儲在內(nèi)存中的所有變量都加上標記。然后,它會去掉環(huán)境中的變量以及被環(huán)境中的變量引用的標記。而在此之后再被加上標記的變量將被視為準備刪除的變量,原因是環(huán)境中的變量已經(jīng)無法訪問到這些變量了。最后。垃圾收集器完成內(nèi)存清除工作,銷毀那些帶標記的值,并回收他們所占用的內(nèi)存空間。
2)引用計數(shù)
另外一種垃圾回收機制就是引用計數(shù),這個用的相對較少。引用計數(shù)就是跟蹤記錄每個值被引用的次數(shù)。當聲明了一個變量并將一個引用類型賦值給該變量時,則這個值的引用次數(shù)就是1。相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數(shù)就減1。當這個引用次數(shù)變?yōu)?時,說明這個變量已經(jīng)沒有價值,因此,在在機回收期下次再運行時,這個變量所占有的內(nèi)存空間就會被釋放出來。
這種方法會引起循環(huán)引用的問題:例如: obj1和obj2通過屬性進行相互引用,兩個對象的引用次數(shù)都是2。當使用循環(huán)計數(shù)時,由于函數(shù)執(zhí)行完后,兩個對象都離開作用域,函數(shù)執(zhí)行結(jié)束,obj1和obj2還將會繼續(xù)存在,因此它們的引用次數(shù)永遠不會是0,就會引起循環(huán)引用。
這種情況下,就要手動釋放變量占用的內(nèi)存:
(3)減少垃圾回收
雖然瀏覽器可以進行垃圾自動回收,但是當代碼比較復雜時,垃圾回收所帶來的代價比較大,所以應該盡量減少垃圾回收。
對數(shù)組進行優(yōu)化: 在清空一個數(shù)組時,最簡單的方法就是給其賦值為[ ],但是與此同時會創(chuàng)建一個新的空對象,可以將數(shù)組的長度設置為0,以此來達到清空數(shù)組的目的。
對object進行優(yōu)化: 對象盡量復用,對于不再使用的對象,就將其設置為null,盡快被回收。
對函數(shù)進行優(yōu)化: 在循環(huán)中的函數(shù)表達式,如果可以復用,盡量放在函數(shù)的外面。