@[toc]
導語
- 什么是V8纺腊?
- V8 js運行的引擎(類似 java運行在jvm上)
- 為什么要關注內存畔咧?
- 防止頁面占用內存過大茎芭,引起客戶端卡頓,甚至無響應誓沸。
- Node 使用的也是V8梅桩,內存對于后端服務的性能至關重要,因為服務的持久性拜隧,后端更容易造成內存溢出宿百。
- 面試裝逼神器。
一洪添、V8引擎如何回收垃圾
1垦页、V8的內存分配
(1)內存大小
內存的大小和操作系統(tǒng)有關,64位為1.4G干奢,32位為0.7G外臂。
- 64位下新生代的空間為 64MB ,老生代為 1400MB律胀。
- 32位下新生代的空間為 16MB 宋光,老生代為 700MB。
- 為什么只設置 1.4G ? 而不是2G炭菌、3G...
- 1罪佳、js最初設計是在瀏覽器上跑的,瀏覽器上的js不持久黑低,運行完代碼就可以了赘艳,所以 1.4G 完全夠用。
- 2克握、js有垃圾回收機制蕾管,回收時會暫停所有代碼的執(zhí)行,(回收300MB大概需要0.5s)菩暗,如果設置為3G掰曾,那回收時間會特別長,程序停止時間過久停团。
(2)新生代和老生代
- 新生代(semi space From & semi space To)簡單地說就是==復制==
- 老生代簡單地說就是==標記刪除整理==
新生代:
- 新生代存放的是 存活時間比較短的變量旷坦,會頻繁發(fā)生垃圾回收。
- 新生代會標記活著的變量佑稠。首先會將 From 中活著的變量 復制到 To 中秒梅,然后將 From 清空,下一次會將 To 中活著的變量 復制到 From 中舌胶,并將 To 清空捆蜀。
- 這是典型的 ==犧牲空間,獲取時間== 算法
- 因為做清空是很快的,而一個一個刪除然后整理是很慢的(內存是連著的辆它,刪除一個變量誊薄,就需要將后面的變量向前復制,然后刪除原來的娩井,整理很慢)
老生代:
- 老生代會標記死掉的變量,做刪除似袁、整理(碎片整理)的操作洞辣。
-
數(shù)組是需要連續(xù)的內存空間,整理很耗時間
晉升機制:
- 剛開始定義的變量都是新生代昙衅,當變量在新生代經歷過一次回收扬霜,就擁有資格晉升為老生代(但不會直接放入老生代)。
- 直到新生代 To(From) 空間已經使用超過 20% 而涉,那么就會晉升到老生代空間著瓶。
2、變量處理
- 內存主要就是存儲變量等數(shù)據的
- 局部變量當程序執(zhí)行結束啼县,且沒有引用的時候就會死掉
- 全局對象會始終存活到程序運行結束
eg:
function f () {
var a = ''
}
f(); // f 執(zhí)行結束 a 就會被回收
function f () {
var a = '';
return a;
}
var b = f(); // f 執(zhí)行結束 a 不會被回收材原,因為外層作用域還有 a 的引用 b。
二季眷、如何查看V8內存使用情況
1余蟹、使用 node 來查看內存使用情況
-
通過
process.memoryUsage()
- rss: V8申請到的總占用空間
- heapTotal: 堆總內存
- heapUsed: 已使用的內存
- external: node專有(底層是c,額外申請到的c++內存 )
2子刮、在 chorme 瀏覽器中查看內存使用情況
-
通過
window.performance
三威酒、內存優(yōu)化實例
1、優(yōu)化內存技巧
- (1)盡量不要定義全局變量
- (2)全局變量記得銷毀掉
a = undefined
delete a;
不建議使用挺峡,嚴格模式下會出問題
- (3)用匿名自執(zhí)行函數(shù)變全局為局部
(function () {}())
eg:
function getme () {
var mem = process.memoryUsage();
var format = function (bytes) {
return (bytes / 1024 / 1024).toFixed(2) + 'MB';
}
console.log('heapTotal: ' + format(mem.heapTotal) + 'heapUsed: ' + format(mem.heapUsed));
}
var size = 20 * 1024 * 1024;
var arr1 = new Array(size);
var arr2 = new Array(size);
var arr3 = new Array(size);
var arr4 = new Array(size);
var arr5 = new Array(size);
var arr6 = new Array(size);
var arr7 = new Array(size);
var arr8 = new Array(size);
var arr9 = new Array(size);
getme(); // 內存溢出 極限 8 個
function getme () {
var mem = process.memoryUsage();
var format = function (bytes) {
return (bytes / 1024 / 1024).toFixed(2) + 'MB';
}
console.log('heapTotal: ' + format(mem.heapTotal) + 'heapUsed: ' + format(mem.heapUsed));
}
var size = 20 * 1024 * 1024;
function a () {
var arr1 = new Array(size);
var arr2 = new Array(size);
var arr3 = new Array(size);
var arr4 = new Array(size);
var arr5 = new Array(size);
var arr6 = new Array(size);
var arr7 = new Array(size);
var arr8 = new Array(size);
}
a();
var arr9 = new Array(size);
getme(); // 內存不會溢出
2葵孤、關于閉包和內存使用
首先重要的是:==閉包并不會影響內存==
雖然在某一版(很久遠了)的 《Javascript 權威指南》中作者說過閉包會占用內存,讓盡量避免閉包橱赠。因為當時 IE5 存在這個 BUG 尤仍,所以才導致這個問題。現(xiàn)在的V8是沒有這個問題的狭姨,所以這是錯誤的說法吓著。
eg:
function getme () {
var mem = process.memoryUsage();
var format = function (bytes) {
return (bytes / 1024 / 1024).toFixed(2) + 'MB';
}
console.log('heapTotal: ' + format(mem.heapTotal) + 'heapUsed: ' + format(mem.heapUsed));
}
for (let i = 10000; i < 10100; i++) {
setTimeout(function () {
console.log(i);
getme(); // 內存占用 4.x MB
})
}
// 閉包形式
for (let i = 10000; i < 10100; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
getme(); // 內存占用 4.x MB
})
})(i)
}