JS會在建立變量時自動分配內存,在不使用的時候會自動週期性的釋放內存,釋放的過程就叫 "垃圾回收"。這個機制有好的一面,固然也也有很差的一面。一方面自動分配內存減輕了開發者的負擔,開發者不用過多的去關注內存使用,可是另外一方面,正是由於由於是自動回收,因此若是不清楚回收的機制,會很容易形成混亂,而混亂就很容易形成"內存泄漏".因爲是自動回收,因此就存在一個 "內存是否須要被回收的" 的問題,可是這個問題的斷定在程序中意味着沒法經過某個算法去準確完整的解決,後面探討的回收機制只能有限的去解決通常的問題。javascript
垃圾回收對是否須要回收的問題主要依賴於對變量的斷定是否可訪問,由此衍生出兩種主要的回收算法:html
標記清理是js最經常使用的回收策略,2012年後全部瀏覽器都使用了這種策略,此後的對回收策略的改進也是基於這個策略的改進。其策略是:java
引用計數策略相對而言不經常使用,由於弊端較多。其思路是對每一個值記錄它被引用的次數,經過最後對次數的判斷(引用數爲0)來決定是否保留,具體的規則有git
最重要的問題就是,循環引用 的問題github
function refProblem () { let a = new Object(); let b = new Object(); a.c = b; b.c = a; //互相引用 }
根據以前提到的規則,兩個都互相引用了,引用計數不爲0,因此兩個變量都沒法回收。若是頻繁的調用改函數,則會形成很嚴重的內存泄漏。算法
V8的回收機制基於 分代回收機制 ,將內存分爲新生代(young generation)和老生代(tenured generation),新生代爲存活時間較短的對象,老生代爲存活時間較長或者常駐內存的變量。瀏覽器
V8將堆分紅了幾個不一樣的區域閉包
老生代(Old Space/Old Generation):大多數在新生區存活一段時間後的對象會轉移至此,採用的回收算法爲 標記清除 & 整理(Mark-Sweep & Mark-Compact,Major GC) 算法,內部再細分爲兩個空間ide
Scavenge 算法是新生代空間中的主要算法,該算法由 C.J. Cheney 在 1970 年在論文 A nonrecursive list compacting algorithm 提出。
Scavenge 主要採用了 Cheney算法,Cheney算法新生代空間的堆內存分爲2塊一樣大小的空間,稱爲 Semi space,處於使用狀態的成爲 From空間 ,閒置的稱爲 To 空間。垃圾回收過程以下:函數
以前說過,標記清除策略會產生內存碎片,從而影響內存的使用,這裏 標記整理算法(Mark-Compact)的出現就能很好的解決這個問題。標記整理算法是在 標記清除(Mark-Sweep )的基礎上演變而來的,整理算法會將活躍的對象往邊界移動,完成移動後,再清除不活躍的對象。
因爲須要移動移動對象,因此在處理速度上,會慢於Mark-Sweep。
爲了不應用邏輯與垃圾回收器看到的邏輯不同,垃圾回收器在執行回收時會中止應用邏輯,執行完回收任務後,再繼續執行應用邏輯。這種行爲就是 全停頓,停頓的時間取決與不一樣引擎執行一次垃圾回收的時間。這種停頓對新生代空間的影響較小,但對老生代空間可能會形成停頓的現象。
爲了解決全停頓的現象,2011年V8推出了增量標記。V8將標記過程分爲一個個的子標記過程,同時讓垃圾回收標記和JS應用邏輯交替進行,直至標記完成。
內存泄漏的問題難以察覺,在函數被調用不少次的狀況下,內存泄漏多是個大問題。常見的內存泄漏主要有下面幾個場景。
function hello (){ name = 'tom' } hello();
未聲明的對象會被綁定在全局對象上,就算不被使用了,也不會被回收,因此寫代碼的時候,必定要記得聲明變量。
let name = 'Tom'; setInterval(() => { console.log(name); }, 100);
定時器的回調經過閉包引用了外部變量,若是定時器不清除,name會一直佔用着內存,因此用定時器的時候最好明白本身須要哪些變量,檢查定時器內部的變量,另外若是不用定時器了,記得及時清除定時器。
let out = function() { let name = 'Tom'; return function () { console.log(name); } }
因爲閉包會常駐內存,在這個例子中,若是out一直存在,name就一直不會被清理,若是name值很大的時候,就會形成比較嚴重的內存泄漏。因此必定要慎重使用閉包。
mounted() { window.addEventListener("resize", () => { //do something }); }
在頁面初始化時綁定了事件監聽,可是在頁面離開的時候未清除事監聽,就會致使內存泄漏。
文章爲參考資料總結的筆記文章,我最近在重學js,會將複習總結的文章記錄在Github,戳這, 有想一塊兒複習的小夥伴可一塊兒參與複習總結!