v8引擎內(nèi)存結(jié)構(gòu)
- 內(nèi)存分配:棧空間,堆空間
- 棧空間:代碼運(yùn)行的環(huán)境(邏輯運(yùn)行的環(huán)境
- 堆空間:所有函數(shù)和引用類型數(shù)據(jù)存放的具體地址
- 堆空間有哪些部分:
1. New Space(Young generation)新生代,
新生代內(nèi)存大小為:
新生代會(huì)將內(nèi)存完全平分為兩個(gè)部分:
Semi space from, Semi space to
2. Old Space(Old Generation) 老生代,
3. Large object space 大對(duì)象內(nèi)存空間(對(duì)象超過(guò)默認(rèn)大小限制時(shí),塞入Large object space,并且不受GC垃圾回收機(jī)制管理)
4. Code space(即時(shí)編譯器會(huì)把我們已經(jīng)編譯的代碼存在Code Space,隨時(shí)在棧中執(zhí)行)
5. Cell space (單元空間)
6. Property cell space (屬性單元空間)
7. Map space (地圖空間)
- 新生代和老生代內(nèi)存大小
內(nèi)存跟操作系統(tǒng)有關(guān),64位還是32位
64位:新生代空間為64MB,老生代空間為1400MB
32位:新生代空間為32MB,老生代空間為700MB
補(bǔ)充:
1.v8引擎64位總大小為1.4G(1464MB),32位為0.7G(732MB)
2.node(v14之后),v8引擎內(nèi)存為2GB
- 垃圾回收算法
1. 新生代有一種算法
思想:Copy(復(fù)制)
特點(diǎn):短頻快
Scavenge算法:新生代互換
運(yùn)行步驟:當(dāng)定義了變量,首先放到新生代(Semi space from)中,因?yàn)樾律?4M一分為二,只有32M,當(dāng)達(dá)到條件后,會(huì)標(biāo)記Semi sapce from里的變量,判斷是否被引用,然后標(biāo)記是否要被清除,把不需要清除所有內(nèi)容復(fù)制到(Semi space to)空間。 然后將Semi space to 空間與Semi space from互換,情況原來(lái)的Semi space from 空間。
ps:為什么要復(fù)制,因?yàn)闋奚臻g來(lái)?yè)Q時(shí)間。
2. 老生代有兩種算法組合起來(lái)
思想:三步走(標(biāo)記,整理,清除)
Mark-Sweep方法(標(biāo)記清除)
Mark-Compact方法(標(biāo)記整理)
運(yùn)行步驟:
ps:老生代為什么不用復(fù)制,因?yàn)槔仙鷥?nèi)存有1400M,如果用Scavenge算法,那么內(nèi)存需要一分為二,因?yàn)橹?00M的內(nèi)存常常處于閑置狀態(tài)。
- 標(biāo)記清除法
任何引擎,都有垃圾回收機(jī)制的跟節(jié)點(diǎn)(GC Roots),類似于js主線程的window。
掃描引用關(guān)系,被掃描到的變量和對(duì)象就會(huì)給予標(biāo)記,被標(biāo)記的內(nèi)容就是有用的數(shù)據(jù),沒(méi)有掃描到的就是垃圾。
1. 廣度掃描
2. 全停頓標(biāo)記
3. 增量標(biāo)記法 & 三色標(biāo)記法
4. 引用計(jì)數(shù)
ps: 標(biāo)記整理法就是在標(biāo)記清除法的基礎(chǔ)上進(jìn)行整理,把非垃圾數(shù)據(jù)進(jìn)行整理,整理成連續(xù)的不間斷的結(jié)構(gòu),然后清除。(標(biāo)記-整理-清除)
- 增量標(biāo)記法
三色標(biāo)記法
內(nèi)存需求
首先了解v8引擎最大內(nèi)存為2GB
1. 大文件上傳
如果大小超過(guò)2GB,服務(wù)直接宕掉
2. webpack打包內(nèi)
3. vite(多項(xiàng)目集群)
- 為什么v8引擎內(nèi)存最大才2G
1. 前端的不持久化,一般情況下執(zhí)行完就會(huì)被回收
2. js是單線程運(yùn)行的 (如果進(jìn)入垃圾回收,所有的運(yùn)行邏輯都會(huì)暫停 )
3. 垃圾回收機(jī)制限制(官方文檔中,回收1.5G內(nèi)存需要時(shí)間50ms )
- 垃圾回收實(shí)例
function test() {
debugger
var a = 1 // 基本數(shù)據(jù)類型
var b = {} // 引用數(shù)據(jù)類型
var c = { a: a } // 引用數(shù)據(jù)類型
return c
// 如果返回基本類型 例如:return 'ok', 那么直接被回收
// 基本類型如果用參數(shù)獲取返回?cái)?shù)據(jù),那么相當(dāng)于簡(jiǎn)單復(fù)制
// 引用數(shù)據(jù)類型如果用參數(shù)獲取返回?cái)?shù)據(jù),相當(dāng)于獲得堆內(nèi)存地址,最終指向的還是變量c內(nèi)存地址
}
// 情況1
test()
// 情況2
var itest = test()
// 執(zhí)行完test后,c的內(nèi)存會(huì)被回收嗎
// 情況1 只是用了test方法,會(huì)被回收
// 情況2 如果用變量接收,就不會(huì)被回收(閉包)
/**
* 運(yùn)行過(guò)程
* 1. 匿名作用域
* 2. test()入棧
* 3. 創(chuàng)建a變量(棧中)
* 4. 創(chuàng)建b變量(棧中,堆中會(huì)開辟一個(gè)內(nèi)存地址0x111)
* 5. 創(chuàng)建c變量(棧中,堆中會(huì)開辟一個(gè)內(nèi)存地址0x111)
* */
- 為什么要關(guān)注內(nèi)存
1.防止頁(yè)面占用內(nèi)存過(guò)大,引起客戶端卡頓,甚至無(wú)響應(yīng)。
2.Node使用的也是v8,內(nèi)存對(duì)于后端服務(wù)的性能至關(guān)重要,因?yàn)榉?wù)的持久性,后端更容易造成內(nèi)存溢出
ps:v8引擎的標(biāo)記一直在進(jìn)行,但是清除,只有在內(nèi)存滿了,或者達(dá)到某個(gè)條件,GC垃圾回收機(jī)制才會(huì)介入。