1. 程式人生 > >js的垃圾回收機制

js的垃圾回收機制

函數 棧內存 堆內存 模式 bom 但是 跟蹤 運行 訪問

Js具有自動垃圾回收機制。垃圾收集器會按照固定的時間間隔周期性的執行。

JS中最常見的垃圾回收方式是標記清除。

工作原理:是當變量進入環境時,將這個變量標記為“進入環境”。當變量離開環境時,則將其標記為“離開環境”。標記“離開環境”的就回收內存。

工作流程:

1. 垃圾回收器,在運行的時候會給存儲在內存中的所有變量都加上標記。

2. 去掉環境中的變量以及被環境中的變量引用的變量的標記。

3. 再被加上標記的會被視為準備刪除的變量。

4. 垃圾回收器完成內存清除工作,銷毀那些帶標記的值並回收他們所占用的內存空間。

引用計數 方式

工作原理:跟蹤記錄每個值被引用的次數。

工作流程:

1. 聲明了一個變量並將一個引用類型的值賦值給這個變量,這個引用類型值的引用次數就是1。

2. 同一個值又被賦值給另一個變量,這個引用類型值的引用次數加1.

3. 當包含這個引用類型值的變量又被賦值成另一個值了,那麽這個引用類型值的引用次數減1.

4. 當引用次數變成0時,說明沒辦法訪問這個值了。

5. 當垃圾收集器下一次運行時,它就會釋放引用次數是0的值所占的內存。

但是循環引用的時候就會釋放不掉內存。循環引用就是對象A中包含另一個指向對象B的指針,B中也包含一個指向A的引用。

因為IE中的BOM、DOM的實現使用了COM,而COM對象使用的垃圾收集機制是引用計數策略。所以會存在循環引用的問題。

解決:手工斷開js對象和DOM之間的鏈接。賦值為null。IE9把DOM和BOM轉換成真正的JS對象了,所以避免了這個問題。

什麽情況會引起內存泄漏?
雖然有垃圾回收機制但是我們編寫代碼操作不當還是會造成內存泄漏。

1. 意外的全局變量引起的內存泄漏。

原因:全局變量,不會被回收。

解決:使用嚴格模式避免。

2. 閉包引起的內存泄漏

原因:閉包可以維持函數內局部變量,使其得不到釋放。

解決:將事件處理函數定義在外部,解除閉包,或者在定義事件處理函數的外部函數中,刪除對dom的引用。

3. 沒有清理的DOM元素引用

原因:雖然別的地方刪除了,但是對象中還存在對dom的引用

解決:手動刪除。

4. 被遺忘的定時器或者回調

原因:定時器中有dom的引用,即使dom刪除了,但是定時器還在,所以內存中還是有這個dom。

解決:手動刪除定時器和dom。

5. 子元素存在引用引起的內存泄漏

原因:div中的ul li 得到這個div,會間接引用某個得到的li,那麽此時因為div間接引用li,即使li被清空,也還是在內存中,並且只要li不被刪除,他的父元素都不會被刪除。

解決:手動刪除清空。

什麽放在內存中?什麽不放在內存中?
基本類型是:Undefined/Null/Boolean/Number/String

基本類型的值存在內存中,被保存在棧內存中。從一個變量向另一個變量復制基本類型的值,會創建這個值的一個副本。

引用類型:object

引用類型的值是對象,保存在堆內存中。

1. 包含引用類型值的變量實際上包含的並不是對象本身,而是一個指向該對象的指針。從一個變量向另一個變量復制引用類型的值,復制的其實是指針,因此兩個變量最終都指向同一個對象。

2. js不允許直接訪問內存中的位置,也就是不能直接訪問操作對象的內存空間。在操作對象時,實際上是在操作對象的引用而不是實際的對象。

棧和堆的區別
  一、堆棧空間分配區別:
  1、棧(操作系統):由操作系統自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧;
  2、堆(操作系統): 一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收,分配方式倒是類似於鏈表。
  二、堆棧緩存方式區別:
  1、棧使用的是一級緩存, 他們通常都是被調用時處於存儲空間中,調用完畢立即釋放;
  2、堆是存放在二級緩存中,生命周期由虛擬機的垃圾回收算法來決定(並不是一旦成為孤兒對象就能被回收)。所以調用這些對象的速度要相對來得低一些。
  三、堆棧數據結構區別:
  堆(數據結構):堆可以被看成是一棵樹,如:堆排序;
  棧(數據結構):一種先進後出的數據結構。

js的垃圾回收機制