Js內存回收

Javascript的世界中,隱藏了不少內存陷阱,不能獲得合理釋放的內存會埋下各類隱患,本文旨在以實用角度去解讀Js涉及到的內存,且看勇士如何鬥惡龍~javascript

 

    本文能夠看作是以前那篇勇士鬥惡龍之沒那麼複雜的Js閉包的後續篇,在思考閉包中內存的問題時,有了寫此文的衝動. 前端

    學以至用,從實用的角度出發咱們最須要關注的就是內存回收用什麼用處?咱們平常工做中好像不須要咱們本身去處理Javascript中的內存,它會自動回 收的.若是你問Javascript內存回收,必定會有TX鄙視的告訴你,這個會自動回收,不須要咱們本身處理. java

   Javascript中的內存,真的不須要咱們關注嗎??? 程序員

    一般這種自問自答的結果,就是會給出一個與問題相反的答案,也就是固然須要!Javascript雖然會自動處理內存,但不是完美的,它存在必定的缺陷.另外一方面,咱們不能由於無知而無畏,由於可能不少莫名其妙的問題就是這樣出現的. 算法

    內存-那些咱們忽略的就是咱們要拯救的 編程

    在平時的編碼中咱們無時無刻不在執行這樣的一個過程,分配內存 -> 使用內存 -> 回收內存.如此反覆的過程在不斷持續着,每個數字,字符串,對象,數組,方法都佔用着計算機的內存.前端編程由於你的Js代碼大部分運行在客戶端瀏覽 器,因此雖然你沒有佔用服務器的內存,但是你佔用了使用者的內存.即便在硬件配置愈來愈高的今天,也不能徹底保證咱們產品的使用者不是古老的機器,何況你 也應該考慮到移動手機的性能.也不是說每一臺機器都配有4G以上的內存供你揮霍,我一直認爲好的程序員對待內存要保持一個吝嗇的心態. 數組

    Javascript在分配內存這一過程當中,會根據不一樣的數據類型進行分配.像基本數據類型會分配在棧內存,引用數據類型分配在堆內存中.引用對於理解內存是一個很重要的概念,我最先對引用的理解來自於C裏面的指針,最好找資料仔細瞭解一下. 瀏覽器

?
1
2
3
4
var obj = {name: "benze" };
var car = obj;
//這裏car就是指向了obj所建立的那個對象所在的內存空間,也就是說此時obj和car都指向了同一塊內存.
//在內存管理的環境中,若是一個對象有權限去訪問另外一個對象,就叫作一個對象引用另外一個對象

        

    咱們平時在使用定義變量,函數或者對象的時候,都在進行各類的內存分配,可是一般不須要寫代碼去回收,由於咱們知道它是自動回收的.這裏我得強調,自動不表明咱們就不要考慮內存回收了. 服務器

    使用內存-也就是那些讀讀寫寫
閉包

    關於內存的使用,個人理解就是對於已經開闢好內存空間的那些值,進行一些讀寫操做.這一過程當中可能還有對象引用的改變等等,由於這個不是本文重點,不加以贅述.

    內存回收 === 屠龍之術?

    話說古時候有人散盡家財學的屠龍之術,技成以後卻發現無龍可屠.那Javascript既然有着自動回收的內存管理,咱們學習內存回收豈不也是同樣,反正 它能正常回收就行唄,咱們管它是怎麼回收的呢.可是問題是我以前提到過,Javascript的垃圾回收機制有必定的侷限性和缺陷,有一些狀況會使得內存 得不到釋放而持續增長,這時候咱們就須要人爲的處理它.

    引用計數的回收機制

    上文提到過引用的概念,Javascript的內存回收的算法主要就依賴於引用,當代碼生成一個新的內存駐留項時(如一個對象),系統就會爲它開闢一塊內 存空間.由於這個對象可能會被傳遞給其餘函數,或者對象.因此可能不少代碼都會指向這個對象的內存空間.javascript的垃圾回收器跟蹤這些指向, 當最後一個指向都被斷開廢棄的時候,這個對象所佔用的空間就會被釋放.

    這是一種比較簡單而且清晰的算法,看上去感受沒什麼問題,可是若是出現這種狀況呢?

 

?
1
2
3
4
var a = {name: 'a' };
var b = {name: 'b' };
a.bname = b
b.aname = a;

    代碼看着很彆扭是吧,可是若是真有這種狀況呢,彼此引用.這樣的狀況,javascript的的回收就對a和b沒有辦法了.對於這種循環引用,實在是各種垃圾自動回收的缺陷.

    真實狀況的內存沒法回收

    也許上面說的那種狀況對於你來講永遠不可能發生,平時注意點也許就避開了,可是總有些狀況,也許你寫了好久本身都沒發現.在稍微舊一點版本的IE下,Javascript的對象是經過標記清除的,BOM和DOM對象倒是經過引用計數,涉及到DOM或者BOM的時候就容易出現循環引用.上代碼瞅瞅:

 

?
1
2
3
4
5
6
<span></span>$(document).ready( function (){
   var div = document.getElementById( "mydiv" );
   div.onclick = function (){
     console.log( "div" );
   }
});<span></span>

    當指定的單擊事件處理程序時,建立了一個在其封閉的環境中包含div變量的閉包環境.而div也包含一個指向閉包的引用(onclick屬性自身),這就致使了內存都不能獲得釋放.固然解決方法很簡單:

?
1
2
3
4
5
6
7
$(document).ready( function (){
   var div = document.getElementById( "mydiv" );
   div.onclick = saydiv;
});
function saydiv(){
    console.log( "div" );
}

    此時由於saydiv函數不在包含div的引用,因此沒有造成循環,內存能夠獲得釋放.

    可能不少人都知道將一個對象置爲null,那麼它的內存就會回收.這是由於變量的指向了一個null,那麼它原來指向的那塊內存空間就會由於沒有被指向,或者說沒有被引用,而被垃圾回收掉.

    標記清除-手動內存回收居然仍是屠龍之術?

    從2012年起現代瀏覽器中,對於Javascript垃圾回收的機制進行了更新.再也不使用引用計數的算法,而是改成使用標記清除的方式.好比定義一個變 量,那麼當它進入執行環境時,會被垃圾回收器標記爲"進入環境",當其離開環境好比函數執行完畢的時候,標記爲"離開環境".垃圾回收機器就會在這些"離 開環境"的變量中挑選出來須要回收掉的變量用於釋放內存.

    這存在一個挑選標準,它不會再去計 算引用的數量.而是從全局對象(根節點)開始尋找,找到全部可得到的對象和全部不可得到的對象.也就是它從以前判斷"對象是否被須要"變成"對象是否能夠 得到".這麼理解,零引用的對象老是不可得到的,可是不可能得到的對象不必定零引用.

    如此除了在比較低版本的IE的狀況下,Javascript的自動回收機制就足以應付大多數狀況了.在高級一點的IE中對於內存回收也有很大的進步,因此仍是推薦大多數狀況下不要手工的回收垃圾.

    尾筆

    原本不打算寫這段尾筆,不過爲了不本文有有始無終的嫌疑,仍是要補充說明一下.首先是大部分現代瀏覽器都已經對內存作了很好的處理,因此大多數狀況下不 須要咱們手工執行.其次本文的目的在於概括總結,而不是非要寫出什麼特殊東東.最後寫此文也是爲了給我本身和看過的人提個醒:

    1. 不要由於是Web的前端就忽視了內存這個因素,更別覺得全部人的電腦都會配有2G乃至4G的內存.
    2. 本文最大的做用是指出一些可能存在的陷阱,不是告訴你們掉進去怎麼辦,而是怎樣避免掉進去.
    3. 循環引用,閉包,DOM操做,這3點是我認爲最容易形成內存問題.
    4. 別由於你歷來沒遇到Javascript內存的問題而忽視乃至忘卻它,優秀的程序員應該吝嗇計算機的資源.
相關文章
相關標籤/搜索