1. 程式人生 > >面試題——js垃圾回收機制和引起記憶體洩漏的操作

面試題——js垃圾回收機制和引起記憶體洩漏的操作

JS的垃圾回收機制瞭解嗎?

       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、堆是存放在二級快取中,生命週期由虛擬機器的垃圾回收演算法來決定(並不是一旦成為孤兒物件就能被回收)。所以呼叫這些物件的速度要相對來得低一些。
  三、堆疊資料結構區別:
  堆(資料結構):堆可以被看成是一棵樹,如:堆排序;
  棧(資料結構):一種先進後出的資料結構。