V8 的內(nèi)存限制是多少的烁,為什么 V8 這樣設(shè)計(jì)奶镶?
64 位
系統(tǒng)下是 1.4GB
迟赃,32 位
系統(tǒng)下是 0.7GB
陪拘。因?yàn)?code>V8最初是為瀏覽器而設(shè)計(jì)的,1.4G
通常普遍夠用了纤壁,而 1.5GB
的垃圾回收堆內(nèi)存左刽,V8
需要 花費(fèi)50 毫秒
以上,做一次非增量式
的垃圾回收甚至要1 秒
以上酌媒。這是垃圾回收中引起Javascript
線程暫停執(zhí)行的事件欠痴,在這樣的花銷下,應(yīng)用的性能和影響力都會(huì)直線下降秒咨。
但之后喇辽,增量標(biāo)記
會(huì)優(yōu)化這一塊的垃圾回收,所以這樣的性能問(wèn)題很少再出現(xiàn)了雨席。
js中對(duì)象的生命周期
- 分配對(duì)象內(nèi)存
- 使用內(nèi)存
- 釋放內(nèi)存
在node
中采用js
中使用的內(nèi)存菩咨,因?yàn)?code>node是基于V8
構(gòu)建的,所以內(nèi)存是通過(guò)V8
引擎方向來(lái)進(jìn)行分配和管理的陡厘。
V8 垃圾回收機(jī)制
V8
在分配對(duì)象空間時(shí)抽米,將其堆內(nèi)存分為新生代和老生代兩個(gè)區(qū)域,根據(jù)對(duì)象的存活時(shí)間長(zhǎng)短糙置,將對(duì)象分為新生代對(duì)象(存活時(shí)間較短的對(duì)象)和老生代對(duì)象(存活時(shí)間較長(zhǎng)的對(duì)象)缨硝,并放入到對(duì)應(yīng)的區(qū)域中。在不同的區(qū)域中采用不同的算法去進(jìn)行垃圾回收
新生代垃圾回收
新生代中存放存活時(shí)間較短的對(duì)象罢低,因?yàn)檫@個(gè)區(qū)域的對(duì)象要頻繁操作,考慮性能原因胖笛,設(shè)計(jì)空間就會(huì)比較小网持,一般64bit
的大約32M
左右。
在新生代中长踊,采用Scanvege
算法功舀,將新生代的空間分為兩個(gè)大小一樣的From
(也稱為對(duì)象區(qū)域)和To
(空閑區(qū)域)兩個(gè)空間,From
空間用來(lái)存放存活的對(duì)象身弊,而To
空間則空置辟汰。
清理過(guò)程如下:
- 將申請(qǐng)空間的對(duì)象放入
From
空間,并將其做標(biāo)記 - 在
From
空間即將滿時(shí)阱佛,會(huì)觸發(fā)垃圾回收帖汞,此時(shí)將仍存活的對(duì)象,移動(dòng)到To
空間凑术,并對(duì)其排序翩蘸,使其不存在內(nèi)存碎片,方面后續(xù)大對(duì)象連續(xù)存儲(chǔ)淮逊;將From
空間清空 - 將
From
空間和To
空間角色對(duì)換催首,繼續(xù)使用
這樣就能保證新生代的垃圾回收完成扶踊,還能使這兩塊空間無(wú)限重復(fù)利用下去。因?yàn)樾律目臻g有限郎任,如果一直增量下去秧耗,空間總會(huì)很快被填滿的,為此舶治,V8
采用了晉升策略分井,即經(jīng)過(guò)2
次垃圾回收仍存活的對(duì)象,將晉升為老生代對(duì)象歼疮,會(huì)被移動(dòng)到老生代區(qū)域中
老生代垃圾回收
標(biāo)記-清除
老生代最初是采用標(biāo)記-清除
算法來(lái)進(jìn)行垃圾回收的:
- 標(biāo)記:從一組根元素開(kāi)始杂抽,遞歸遍歷這組根元素,在遍歷過(guò)程中韩脏,能到達(dá)的對(duì)象則為存活對(duì)象缩麸,不能到達(dá)的則標(biāo)記為垃圾對(duì)象(即添加垃圾標(biāo)記)
- 清除:在清除階段,會(huì)將標(biāo)記階段中標(biāo)記的垃圾對(duì)象給清除掉
在完成垃圾回收后赡矢,老生代空間中會(huì)存在大量不連續(xù)的空間杭朱,從而導(dǎo)致可能沒(méi)有足夠的連續(xù)空間存儲(chǔ)大對(duì)象
標(biāo)記-整理
為了解決標(biāo)記-清除算法的弊端,從而就產(chǎn)生了標(biāo)記-整理
算法:
- 標(biāo)記階段同標(biāo)記-清除的第一階段不變
- 整理:在整理階段吹散,是將沒(méi)有帶有垃圾標(biāo)記的對(duì)象全給移動(dòng)到內(nèi)存的一端弧械,然后清除端邊界以外的內(nèi)存,從而保證內(nèi)存的連續(xù)存儲(chǔ)空間
增量標(biāo)記算法
為什么要使用增量標(biāo)記算法空民?
因?yàn)?code>JavaScript是單線程的刃唐,而且是在主線程上運(yùn)行的,一旦執(zhí)行垃圾回收界轩,就會(huì)阻塞JavaScript
腳本運(yùn)行画饥,直至垃圾回收完成后,JavaScript
腳本才繼續(xù)執(zhí)行浊猾,這種因垃圾回收造成的阻塞抖甘,我們稱為 全停頓
新生代內(nèi)的空間較小,垃圾回收很快葫慎,造成的全停頓用戶基本感知不到衔彻,所以影響不大。
但老生代的空間大偷办,對(duì)象多艰额,垃圾回收就慢,就如我們剛開(kāi)始說(shuō)的椒涯,如果1.5G
的內(nèi)存空間垃圾回收造成的全停頓大約在50ms
以上悴晰,就會(huì)造成頁(yè)面卡頓,帶來(lái)不好的用戶體驗(yàn)。
為了解決這個(gè)問(wèn)題铡溪,增量標(biāo)記算法就產(chǎn)生了:
-
V8
將標(biāo)記過(guò)程分為一個(gè)個(gè)小的子標(biāo)記過(guò)程漂辐,當(dāng)子標(biāo)記部分完成后,立即執(zhí)行垃圾回收 - 這樣棕硫,小部分的垃圾回收和
JavaScript
交替執(zhí)行髓涯,用戶就不會(huì)感知到因?yàn)槔厥斩鴮?dǎo)致的卡頓了