棧
- 定義
棧用來在函數執行時存儲保存執行上下文環境,我們一般也稱調用棧,如基本類型的變量,引用類型的引用地址等都保存在棧中。執行到當前函數時進行入棧,執行完畢進行出棧。 - 回收方式
有一個記錄當前執行狀態的指針(稱爲ESP
)指向活動棧,函數執行完畢,esp
下移到後一節點,銷燬當前函數執行上下文。新的函數執行上下文入棧直接覆蓋掉銷燬的空間即可 .
function test() {
const a = { name: 'a' };
function showName() {
const b = { name: 'b' };
}
showName();
}
test();
堆
-
定義
對象的值等大數據保存在堆中。 -
回收方式
使用 JavaScript 中的垃圾回收器進行回收,通過標記的方式進行回收。
採用 可訪問性(reachablility)算法來判斷堆中的對象是否爲活動對象。這個算法其實就將一些GC Root
作爲初始存活對象的集合,從GC Root
對象觸發,遍歷GC Root
中的所有對象- 能夠通過
GC Root
(全局 wimdow 、dom樹、棧上的變量、回收非活動對象佔據的內存)遍歷到的對象會被認爲是可訪問的,我們將其標記爲活動對象
,必須保留 - 如果一個對象無法通過 GC Root 遍歷到,那麼就認爲這個對象是不可訪問的,可能需要被回收,並標記爲
非活動對象
。
- 能夠通過
堆的垃圾回收
在垃圾回收領域有一個代際假說
的概念,大致意思就是數據分爲生命週期短的和長久的。
根據代際假說,v8對堆的數據保存分爲新生代區域
,老生代區域
兩大塊。這兩區域的垃圾回收是不同的,分別爲副垃圾回收器
和主垃圾回收器
。
-
新生代區域
存儲空間小,不能存放大對象 -
老生代區域
空間大,存活時間長。新生代經過2次GC仍存活的的變量 -
副垃圾回收器
通過將新生代區域平分爲2塊區域:對象區
、空閒區
。當活動區
中內存滿時啓動垃圾回收,遍歷對象進行垃圾標記,將活動
的對象複製到空閒區
,移動到空閒區的對象是按順序來的,因此不用去整理。處理完後,將對象區
與空閒區
翻轉,完成垃圾回收。複製操作需要時間成本,因此爲了效率,空間一般設置的很小。空間小,容易填滿,因此又採用了對象晉升策略
,經過兩次垃圾回收依然存活的對象就會被移動到老生區 -
主垃圾回收器
採用標記-清除(Mark-Sweep)
的算法進行垃圾回收。解決標記-清除
空間不連續引入標記-整理(Mask-Compact)
,標記完後,先將所有存活的對象向一端移動,然後直接清理掉這一端以外的內存。
優化效率
-
併發標記
: 在主程序運行階段,併發的對變量進行標記
處理,防止中斷js主線程。筆辯主線程、輔助線程同時修改同一對象,需實現讀寫鎖等功能。 -
並行整理
:進行整理時佔用主線程,在此基礎上,啓動多個輔助線程一起處理,加快速度。 -
增量整理
:由於在整理時是佔用的主線程,會阻塞js運行,因此通過增量的方式,將一次處理分成多個小任務處理,減小對用戶的影響。js運行與標記相互交叉,防止變量引用在a,b之間變換,造成標記失敗,使用黑白灰
三色標記法進行處理。 -
黑白灰
三色標記- 黑:節點以及子節點已處理完
- 灰:正在處理的節點。黑節點的子節點不能爲白節點,直接置灰(寫屏障)
- 白: 非活動對象,等待回收