1.JS垃圾回收有幾種方式
2.什麼方式會引發內存泄露
3.如何避免內存泄漏,有幾種方式
4.JS的棧內存和堆內存
複製代碼
垃圾回收的方式
原理:垃圾收集器會按期(週期性)找出那些不在繼續使用的變量,而後釋放其內存。程序員
JS具備自動垃圾回收機制,GC(Garbage collection)不是實時的,由於開銷比較大,因此回收會按照固定的時間間隔週期性執行。算法
- 回收方法一:標記清除
- 當變量進入環境時,標記爲「進入環境」,離開環境時,標記爲「離開」
- 垃圾回收器在運行的時候會給存儲在內存中的全部變量都加上標記(固然,可使用任何標記方式)。
- 而後,它會去掉環境中的變量以及被環境中的變量引用的變量的標記(閉包)。
- 而在此以後再被加上標記的變量將被視爲準備刪除的變量,緣由是環境中的變量已經沒法訪問到這些變量了。
- 最後,垃圾回收器完成內存清除工做,銷燬那些帶標記的值並回收它們所佔用的內存空間。
- 回收方法二:引用計數
- IE七、8是用的這種方式,不推薦,IE9把DOM和BOM轉換爲真正的JS對象了,因此再也不使用引用計數
- IE中的DOM和BOM的實現使用了C++的COM,而COM的回收機制是引用計數
- 原理:跟蹤記錄每一個值被引用的次數,當聲明一個變量,並將這個引用類型的值賦值給該變量時,這個引用類型值的引用次數就是1
- var a = {}; // a的引用次數是1
- 當引用次數變爲0時,就會釋放該內存值佔用的空間
- 循環引用時會形成內存泄露
- 循環引用:對象A中包含指向對象B的指針,B中包含指向A的引用,當程序執行結束,引用計數不爲0,致使沒法釋放A、B
- 解決方案:手動設置爲null,切斷變量與它此前引用的值之間的鏈接,GC在下次運行時,就會刪除這些值,並把它們回收
- 瀏覽器的回收策略--標記清除,可是垃圾收集的時間間隔,各個瀏覽器互不相同。
內存泄漏的狀況
- 內存泄漏:再也不用到的內存,沒有及時釋放
- 引發內存泄露的狀況
- 垃圾回收不會清除全局變量,全局變量會形成內存泄露
- 緣由:局部變量只在函數的執行過程當中存在,而在這個過程當中會爲局部變量在棧或堆上分配相應的空間,以存儲它們的值,而後在函數中使用這些變量,直至函數結束,而閉包中因爲內部函數的緣由,外部函數結束並不能算是結束。 而全局變量的生命週期直至瀏覽器卸載頁面纔會結束。
- 解決方法:使用嚴格模式
- 未銷燬的定時器和回調函數,形成內存泄露
- 定時器的回調函數是個閉包,閉包會形成引用的變量和函數一直保存在內存中,沒法釋放,形成內存泄露
- 解決方法:將事件處理函數定義在外部,解除閉包,或者在定義事件處理函數的外部函數中,刪除對dom的引用。
- DOM元素的不恰當處理
- 雖然別的地方刪除了,但對象中仍是存在對DOM的引用,好比引用了td元素,但刪除了整個表格,實際上td元素仍然保留對其父元素的引用,致使整個表格都沒法回收
- 解決方法:對於DOM元素的引用要及時手動置空
觸發垃圾回收的機制
- IE6--當環境中存在256個變量、4096個對象、64k的字符串任意一種狀況的時候就會觸發垃圾回收器工做
- IE7--觸發條件動態修改,根據垃圾回收期回收的內存分配量和程序的內存量比較
- 垃圾回收時,也沒回中止響應,形成頁面卡頓,如何優化呢?
- 方法1:分代回收
- 變量存儲時區分臨時、持久區域,多回收臨時對象區,少回收持久對象區,減小每次須要遍歷的對象,從而減小每次GC耗時
- 方法2:增量GC
- 每次處理一點,下次再處理一點,雖然耗時短,可是中斷較多,須要上下文頻繁切換。
- 針對不一樣場景,能夠選擇不一樣的處理方案
堆內存和棧內存
JS的數據類型有7中,其中Number、Boolean、String、Null、Symbol都是基本類型,Object、Array是引用類型。數組
- 棧內存保存基本類型的值、指向引用類型的指針,內存大小是固定的
- 堆內存保存的是引用類型的值,如數組和對象,內存大小是不固定的
- 棧內存是先進後出,堆內存是按引用地址讀取
- 操做對象時,實際操做的是對象的引用,而不是實際的對象
- 堆內存由程序員分配,若程序員不釋放,程序結束時會有OS回收,分配方式相似鏈表
- 棧內存由OS自動操做釋放,使用的是一級緩存,被調用時處於存儲空間,調用完畢馬上釋放
- 堆內存放在二級緩存中,生命週期由垃圾回收算法來決定,並非一旦成爲孤兒就會被回收。