javascript不一樣於c、c++的一個特色是:具備自動的垃圾回收機制,這就意味着,開發人員能夠專一於業務,而沒必要把過多精力放在內存的管理上,提升開發效率。
所謂的垃圾回收就是找出那些再也不繼續使用的變量,而後釋放其佔用的內存。爲此,垃圾收集器會按照固定的時間間隔(或代碼執行中預約的收集時間),週期性地執行這一操做。
目前在瀏覽器中,實現垃圾回收的方式主要有兩種:
1.標記清除
也是javascript最經常使用的垃圾回收的方式。
在標記清除的方式中有兩個概念:『進入環境』和『離開環境』。『進入環境』指變量進入執行的環境。『離開環境』指變量完成任務,離開了執行的環境。
垃圾收集器在運行的時候會給存儲在內存中的全部變量都加上標記。而後,它會去掉環境中的變量以及被環境中的變量引用的變量的標記。而在此以後再被加上標記的變量將被視爲準備刪除的變量,緣由是環境中的變量已經沒法訪問到這些變量了。最後,垃圾收集器完成內存清除工做,銷燬那些帶標記的值並回收它們所佔用的內存空間。
2.引用計數
引用計數的含義是跟蹤記錄每一個值被引用的次數。當聲明瞭一個變量並將一個引用類型值賦給該變量時,則這個值的引用次數就是1。若是同一個值又被賦給另外一個變量,則該值的引用次數加 1。相反,若是包含對這個值引用的變量又取得了另一個值,則這個值的引用次數減 1。當這個值的引用次數變成 0 時,則說明沒有辦法再訪問這 個值了,於是就能夠將其佔用的內存空間回收回來。這樣,當垃圾收集器下次再運行時,它就會釋放那 些引用次數爲零的值所佔用的內存。
這種機制其實在js中並不經常使用,由於這種機制會產生循環引用的問題,『循環引用』指的是對象 A 中包含一個指向對象 B 的指針,而對象 B 中也包含一個指向對象 A 的引用。對於像js類的自動回收機制的語言來講,須要額外手動的去釋放內存,其實並不友好。例如,在下面的例子中:javascript
function garbage(){ var A = new Object(); var B = new Object(); A.property = B; B.property = A; }
因爲對象A、B相互引用,引用次數都爲2,因此其佔用的內存並不能被自動釋放。
在IE的BOM和DOM中就採用了此類的引用計數,在IE9之後,微軟轉而使用了標記清除的方式來管理內存,從而避免了兩種方式並存的局面。java
因爲瀏覽器和其餘桌面程序相比,系統分配給瀏覽器的內存相對較少,這樣作的目的主要是出於安全方面的考慮,防止運行 JavaScript 的網頁耗盡所有系統內存而致使系統崩潰。內存限制問題不只會影響給變量分配內存,同時還會影響調用棧以及在一個線程中可以同時執行的語句數量。
所以,確保佔用最少的內存可讓頁面得到更好的性能。而優化內存佔用的最佳方式,就是爲執行中的代碼只保存必要的數據。一旦數據再也不有用,最好經過將其值設置爲 null 來釋放其引用——這個作法叫作解除引用(dereferencing)。這一作法適用於大多數全局變量和全局對象的屬性。局部變量會在它們離開執行環境時自動被解除引用。c++
function createPerson(name){ var localPerson = new Object(); localPerson.name = name; } var globalPerson = createPerson("Nicholas"); // 手工解除 globalPerson 的引用 globalPerson = null;
不過,解除一個值的引用並不意味着自動回收該值所佔用的內存。解除引用的真正做用是讓值脫離 執行環境,以便垃圾收集器下次運行時將其回收。算法
JavaScript 是一門具備自動垃圾收集機制的編程語言,開發人員沒必要關心內存分配和回收問題。可 以對 JavaScript 的垃圾收集例程做以下總結。
離開做用域的值將被自動標記爲能夠回收,所以將在垃圾收集期間被刪除。
「標記清除」是目前主流的垃圾收集算法,這種算法的思想是給當前不使用的值加上標記,然
後再回收其內存。
另外一種垃圾收集算法是「引用計數」,這種算法的思想是跟蹤記錄全部值被引用的次數。JavaScript
引擎目前都再也不使用這種算法;但在 IE 中訪問非原生 JavaScript 對象(如 DOM 元素)時,這種
算法仍然可能會致使問題。
當代碼中存在循環引用現象時,「引用計數」算法就會致使問題。
解除變量的引用不只有助於消除循環引用現象,並且對垃圾收集也有好處。爲了確保有效地回
收內存,應該及時解除再也不使用的全局對象、全局對象屬性以及循環引用變量的引用。編程
---參考《JavaScript高級程序設計第3版》瀏覽器