1. 什么是內存管理
編程中的內存管理涉及控制程序運行時內存的分配和釋放。像許多高級語言一樣,JavaScript通過一個垃圾回收(Garbage collection)的過程使用自動內存管理。這使開發者不必顯式管理內存,但了解內存何時分配和釋放是非常必要的,可以防止內存泄漏和過度消耗內存等問題。
內存生命周期
- 內存分配 - 為變量、對象和函數預留內存的過程。
- 內存使用 - 使用已分配的內存(例如,讀取或寫入變量,調用函數)。
- 內存釋放 - 一旦不再需要內存,就應該將其釋放(在JavaScript中,這是通過垃圾回收(Garbage collection)完成的)。
2. JavaScript中的內存分配
當變量被聲明或創建對象和函數時,JavaScript會自動分配內存。
當我們聲明一個原始值時,JavaScript會為該值分配內存,并直接將值存儲在變量中。原始類型數據直接存儲在棧中,并且具有固定大小。
對于非Primitive Values 當我們創建一個對象、數組或函數時,它們都存儲在堆中,變量包含一個引用(或指針)指向堆中的內存位置。這些類型沒有固定大小,并且可以動態增長。
3. 垃圾回收
JavaScript通過一個垃圾回收的過程自動釋放不再使用的內存。JavaScript引擎用于垃圾回收的最常見算法是:標記和清除算法。
標記和清除算法
它的工作原理如下:
-
標記階段 - 垃圾回收器標記所有可到達的變量和對象(即可從root訪問,如全局變量、當前函數調用棧和事件偵聽器)。這些變量被認為是alive的。
-
清除階段 - 然后它檢查不可到達的變量和對象(即不存在對它們的引用)。這些對象被認為是垃圾,并被移除,然后內存空間得以釋放。
4. 內存泄漏
當不再使用的內存沒有被釋放時,就會發生內存泄漏。這可能導致你的應用程序隨著時間的推移消耗越來越多的內存,導致性能下降甚至崩潰。內存泄漏通常是由于不可到達的對象仍然在代碼的某個部分被引用,垃圾回收器無法移除它們而引起的。
常見的可能發生內存泄露的問題包括:
1.setTimeout和setInterval這樣的定時器沒有被清除。
2.非預期的全局變量 未使用var、let和const聲明變量會被當成隱式聲明的全局變量,這些變量在整個頁面的生命周期內存在,并且不會被垃圾回收。
3.錯誤的使用閉包