這篇文章主要介紹 V8 的內(nèi)存管理和垃圾回收知識(shí)畴椰。(總結(jié)來自網(wǎng)易課堂)
V8引擎內(nèi)存回收機(jī)制
為什么我們要關(guān)注內(nèi)存呢臊诊?
- 防止頁面占用內(nèi)存過大,引起客戶端卡頓迅矛,甚至無響應(yīng)
- Node使用的也是V8妨猩,內(nèi)存對于后端服務(wù)的性能至關(guān)重要。因?yàn)榉?wù)的持久性秽褒,后端很容易造成內(nèi)存溢出壶硅。
V8內(nèi)存結(jié)構(gòu)
在 64 位的機(jī)器上,默認(rèn)最大操作的對象大小約為 1.4G销斟,在 32 位的機(jī)器上庐椒,默認(rèn)最大操作的對象大小約為 0.7G。
V8 將內(nèi)存分為兩類:新生代內(nèi)存空間和老生代內(nèi)存空間蚂踊,新生代內(nèi)存空間主要用來存放存活時(shí)間較短的對象约谈,老生代內(nèi)存空間主要用來存放存活時(shí)間較長的對象。 64位新生代的空間為64MB犁钟,老生代為1400MB棱诱。32位下新生代的空間為16MB,老生代為700MB涝动。
V8內(nèi)存結(jié)構(gòu)
新生代的變量迈勋,是一個(gè)復(fù)制的過程,假設(shè)有a,b,c三個(gè)變量醋粟,如果c不使用了靡菇,就會(huì)把From中的變量a、b復(fù)制到to里面米愿,然后把from里面全部清空厦凤。下一次,如果b死掉了育苟,再把a(bǔ)從to復(fù)制到from较鼓,然后把to清空。
老生代的回收违柏,是標(biāo)記死掉的變量博烂,在垃圾回收的時(shí)候拓哺,把死掉的變量全部清除掉,然后進(jìn)行磁盤碎片處理脖母。
標(biāo)記清除法主要分三步:
- 將所有的指針(變量名)和分配出去的內(nèi)存打上標(biāo)記。
- 從棧區(qū)開始查找所有可用的變量名闲孤,清除這些變量名的標(biāo)記谆级,并且清除它們指向的內(nèi)存的標(biāo)記。
-
標(biāo)記清除結(jié)束后讼积,回收所有仍然帶有標(biāo)記的內(nèi)存(說明沒有一個(gè)有效的變量名指向這塊內(nèi)存)肥照。
image.png
新生代如何晉升到老生代。
必須要滿足2個(gè)條件:
1.變量必須要經(jīng)歷過回收(也就是復(fù)制)
2.To空間已經(jīng)占用了百分之25勤众。
利用node來查看內(nèi)存使用情況
通過process.memoryUsage()
查看V8引擎內(nèi)存
其中res是V8總內(nèi)存舆绎,heapTotal:是堆總內(nèi)存,heapUsed:是堆使用內(nèi)存们颜,external:是額外C++內(nèi)存吕朵。
我們重點(diǎn)關(guān)注一下heapUsed
V8引擎是如何處理變量
內(nèi)存主要是用來儲(chǔ)存變量等數(shù)據(jù),局部變量當(dāng)程序執(zhí)行結(jié)束窥突,且沒有引用的時(shí)候努溃,就會(huì)隨之消失。而全局變量會(huì)始終存貨到程序運(yùn)行結(jié)束阻问。
function getme(){
var mem = process.memoryUsage();
var format = function(bytes){
return (bytes/1024/1024).toFixed(2)+'MB';
};
console.log('Process: heapTotal '+format(mem.heapTotal) +
' heapUsed ' + format(mem.heapUsed) +
' rss ' + format(mem.res)
);
}
上面這個(gè)函數(shù)可以在node環(huán)境中輸出V8內(nèi)存的使用情況梧税。
如何注意內(nèi)存的使用
優(yōu)化內(nèi)存的技巧
- 盡量不要定義全局變量
- 全局變量記得銷毀掉
有兩種方式,第一種是delete称近,但是delete在嚴(yán)格模式下是禁止的第队。
第二種,是將變量 = undefined 或者 變量 = null - 用匿名自執(zhí)行函數(shù)變?nèi)譃榫植?/li>
- 盡量避免閉包
防止內(nèi)存泄漏
- 濫用緩存
- 大內(nèi)存量操作