天天看點

垃圾回收機制

JavaScript是在建立變量(對象,字元串等)時自動進行了配置設定記憶體,并且在不使用它們時“自動”釋放。 釋放的過程稱為垃圾回收。這個“自動”是混亂的根源,并讓JavaScript開發者錯誤的感覺他們可以不關心記憶體管理。

不管什麼程式語言,記憶體生命周期基本是一緻的:

配置設定你所需要的記憶體

使用配置設定到的記憶體(讀、寫)

不需要時将其釋放\歸還

所有語言第二部分都是明确的。第一和第三部分在底層語言中是明确的,但在像JavaScript這些進階語言中,大部分都是隐含的。

為了不讓程式員費心配置設定記憶體,JavaScript 在定義變量時就完成了記憶體配置設定。

使用值的過程實際上是對配置設定記憶體進行讀取與寫入的操作。讀取與寫入可能是寫入一個變量或者一個對象的屬性值,甚至傳遞函數的參數。

大多數記憶體管理的問題都在這個階段。在這裡最艱難的任務是找到“哪些被配置設定的記憶體确實已經不再需要了”。它往往要求開發人員來确定在程式中哪一塊記憶體不再需要并且釋放它。進階語言解釋器嵌入了“垃圾回收器”,它的主要工作是跟蹤記憶體的配置設定和使用,以便當配置設定的記憶體不再使用時,自動釋放它。

垃圾回收機制分為兩種:

引用計數法: 這是最初級的垃圾收集算法。此算法把“對象是否不再需要”簡化定義為“對象有沒有其他對象引用到它”。如果沒有引用指向該對象(零引用),對象将被垃圾回收機制回收。也就是說目前記憶體被占用一次,計數累加一次,移除占用就減1,減到0時,浏覽器就回收它。

标記清除: 這個算法把“對象是否不再需要”簡化定義為“對象是否可以獲得”。最常用的垃圾回收機制就是标記清除,當變量進入執行環境時,被标記為'進入環境',當變量離開執行環境時,被标記為'離開環境'。某一個時刻,垃圾回收器會過濾掉環境中的變量,以及被環境變量引用的變量,剩下的就是被視為準備回收的變量。

記憶體洩露是指當一塊記憶體不再被應用程式使用的時候,由于某種原因,這塊記憶體沒有返還給作業系統或者記憶體池的現象,記憶體洩漏可能會導緻應用程式卡頓或者崩潰。

在js中,常見的記憶體洩漏主要有5種

意外的全局變量

在非嚴格模式中,未定義的變量會被自動綁定到全局對象上(window/global),比如:

函數内部變量沒有定義,自動綁定到全局對象,就相當于 window.bar = 'somthing...',全局變量不會被回收,函數執行完,變量就一直還在記憶體中沒有被釋放。

解決方法: 使用嚴格模式或者在變量使用完畢後設定為 null,以回收記憶體。

2. 閉包

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

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

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

原因:dom元素移除,但對dom元素的引用沒有解除,會導緻記憶體洩漏。

解決:手動删除。

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

原因:當不需要setInterval或者setTimeout時,定時器沒有被clear,定時器的回調函數以及内部依賴的變量都不能被回收,造成記憶體洩漏。

解決:比如:vue使用了定時器,需要在beforeDestroy 中做對應銷毀處理。js也是一樣的

5. 子元素存在引用引起的記憶體洩漏

原因:div中的ul li 得到這個div,會間接引用某個得到的li,那麼此時因為div間接引用li,即使li被清空,也還是在記憶體中,并且隻要li不被删除,他的父元素都不會被删除。

解決:手動删除清空。