垃圾回收機制


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

內存生命周期

不管什么程序語言,內存生命周期基本是一致的:

  • 分配你所需要的內存
  • 使用分配到的內存(讀、寫)
  • 不需要時將其釋放\歸還

所有語言第二部分都是明確的。第一和第三部分在底層語言中是明確的,但在像JavaScript這些高級語言中,大部分都是隱含的。

js內存分配(值的初始化)

為了不讓程序員費心分配內存,JavaScript 在定義變量時就完成了內存分配。

var n = 123; // 給數值變量分配內存
var s = "azerty"; // 給字符串分配內存

var o = {
  a: 1,
  b: null
}; // 給對象及其包含的值分配內存

// 給數組及其包含的值分配內存(就像對象一樣)
var a = [1, null, "abra"];

function f(a){
  return a + 2;
} // 給函數(可調用的對象)分配內存

// 函數表達式也能分配一個對象
someElement.addEventListener('click', function(){
  someElement.style.backgroundColor = 'blue';
}, false)

使用值

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

釋放內存

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

垃圾回收

垃圾回收機制分為兩種:

  • 引用計數法: 這是最初級的垃圾收集算法。此算法把“對象是否不再需要”簡化定義為“對象有沒有其他對象引用到它”。如果沒有引用指向該對象(零引用),對象將被垃圾回收機制回收。也就是說當前內存被占用一次,計數累加一次,移除占用就減1,減到0時,瀏覽器就回收它。
  • 標記清除: 這個算法把“對象是否不再需要”簡化定義為“對象是否可以獲得”。最常用的垃圾回收機制就是標記清除,當變量進入執行環境時,被標記為'進入環境',當變量離開執行環境時,被標記為'離開環境'。某一個時刻,垃圾回收器會過濾掉環境中的變量,以及被環境變量引用的變量,剩下的就是被視為准備回收的變量。

開發過程中遇到的內存泄漏情況:

內存泄露是指當一塊內存不再被應用程序使用的時候,由於某種原因,這塊內存沒有返還給操作系統或者內存池的現象,內存泄漏可能會導致應用程序卡頓或者崩潰。
在js中,常見的內存泄漏主要有5種

  1. 意外的全局變量
    在非嚴格模式中,未定義的變量會被自動綁定到全局對象上(window/global),比如:
function foo() {
  bar= 'somthing...'
}
foo()

函數內部變量沒有定義,自動綁定到全局對象,就相當於 window.bar = 'somthing...',全局變量不會被回收,函數執行完,變量就一直還在內存中沒有被釋放。
解決方法: 使用嚴格模式或者在變量使用完畢后設置為 null,以回收內存。
2. 閉包

function foo() {
  let a =  1  // 外部訪問不到這個變量
  function bar() {
    return a // 這里將變量返回出去
  }
  return bar() // return出來后就給window了所以一直存在內存中。因為一直在內存中,在IE里容易造成內存泄漏
}
foo()

原因:閉包可以維持函數內局部變量,使其得不到釋放。
解決:將事件處理函數定義在外部,解除閉包,或者在定義事件處理函數的外部函數中,刪除對dom的引用。
3. 沒有清理的DOM元素引用
原因:dom元素移除,但對dom元素的引用沒有解除,會導致內存泄漏。
解決:手動刪除。
4. 被遺忘的定時器或者回調
原因:當不需要setInterval或者setTimeout時,定時器沒有被clear,定時器的回調函數以及內部依賴的變量都不能被回收,造成內存泄漏。
解決:比如:vue使用了定時器,需要在beforeDestroy 中做對應銷毀處理。js也是一樣的
5. 子元素存在引用引起的內存泄漏
原因:div中的ul li 得到這個div,會間接引用某個得到的li,那么此時因為div間接引用li,即使li被清空,也還是在內存中,並且只要li不被刪除,他的父元素都不會被刪除。
解決:手動刪除清空。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM