写点什么

NodeJs 深入浅出之旅:V8 内存分配🧙‍♂️

作者:空城机
  • 2021 年 11 月 15 日
  • 本文字数:1834 字

    阅读完需:约 6 分钟

NodeJs 深入浅出之旅:V8 内存分配🧙‍♂️

V8 内存分配

本文紧接上文《NodeJs深入浅出之旅:内存控制(上)》


当在代码中声明变量并赋值时,所使用对象的内存就分配在堆中。如果已申请的堆空闲内存不够分配新的对象,将继续申请堆内存,直到堆的大小超过 V8 的限制。


Node查看内存命令 memoryUsage:此命令是返回描述 Node.js 进程的内存使用量(以字节为单位)的对象, 并且不同的电脑下可能相同项目的进程也会不同。


// 查看可使用内存大小let mU = process.memoryUsage();console.log('内存大小:');console.log(mU);
复制代码


各内存的说明:


小知识:在浏览器的控制台中输入window.performance命令也可以查看内存


其中有三个值,分别是:

jsHeapSizeLimit: 2172649472
totalJSHeapSize: 25233728
usedJSHeapSize: 22200444

  • jsHeapSizeLimit代表内存大小限制, 2172649472/1024/1024 ≈ 2072M,也就是 2G,这也佐证了新的 V8 已经将内存从 1.4G 限制提升上来了。

  • totalJSHeapSize代表可使用内存

  • usedJSHeapSize是 JavaScript 对象占用的内存,不能大于totalJSHeapSize,如果大于,可能出现了内存泄漏


内存主要存储变量等数据:


  • 局部变量当程序执行结束,且没有引用时就会消失

  • 全局对象回始终存活到程序结束运行

手动内存分配

接下来让尝试使用--max-old-space-size进行手动内存分配


首先编写简单的 JavaScript 代码,让代码内存不断增加。

const os = require('os');function getMemory() {    let memory = process.memoryUsage();
// console.log(`系统总内存:${(totalmem/1024/1024).toFixed(1)}MB`); console.log(`申请到内存:${(memory.heapTotal/1024/1024).toFixed(1)}MB`); console.log(`已使用内存:${(memory.heapUsed/1024/1024).toFixed(1)}MB`); console.log('--------------------')}
// 测试内存超出代码let count = 0;
// 每次都会接受一个大数组let useMem = function(){ let size = 20 * 1024 * 1024; let arr = new Array(size); return arr;}
复制代码


接下来开始编写运行方法:

// 全局变量let total = [];for (let j = 0; j < 10; j++) {    getMemory();    total.push(useMem());}console.log('success');
复制代码


以上循环 10 次,是不会超出的,能正常输出success


如果循环 15 次,就会超出,下方出现垃圾回收跟踪日志


其中Last few GCs显示的是最后几次垃圾回收的情况,JS stacktrace代表 JavaScript 的堆栈跟踪。


报错的原因是:JavaScript heap out of memory,达到堆限制分配失败-JavaScript 堆内存不足


对于当前这种情况而言,就可以使用--max-old-space-size命令来扩充堆内存空间了,一般而言新生代内存空间扩充并没有多大必要,堆内存不足主要还是需要扩充老生代的内存。


node 运行js时添加:--max-old-space-size=2698,这可以将老生代内存空间扩充到 2698MB。


命令:node --max-old-space-size=2698 .\getMemory.js,成功的看到了success的输出


这条命令的配置也可以添加在项目的package.json中,可以使用yarn或者npm运行 node 命令

注意: 在分配内存时需要注意系统空闲内存,不能超过系统的空闲内存。并且一般只能接受空闲内存的 75%。可以使用导入os来进行查看。

const os = require('os');
let totalmem = os.totalmem();  // 以整数形式返回系统内存总量(以字节为单位)
let freemem = os.freemem();  // 以整数形式返回空闲的系统内存量(以字节为单位)。
console.log(`系统总内存:${ (totalmem/1024/1024).toFixed(1) },系统空闲内存:${ (freemem/1024/1024).toFixed(1) }`);




查看垃圾回收日志

查看垃圾回收日志的方式主要是在启动时添加--trace_gc参数。 在进行垃圾回收时,将会从标准输出中打印垃圾回收的日志信息


在上面的 node 运行命令中修改:node --trace_gc getMemory.js


此时在终端中出现的就是垃圾回收的日志信息,通过分析垃圾回收日志,可以了解垃圾回收的运行情况,找出哪些阶段比较耗时。



当然此时日志是存在终端,后续查看并不方便,所以可以通过添加> gc.log命令生成 gc.log 文件。命令:node --trace_gc getMemory.js > gc.log


命令运行后终端不会显示日志,但是在文件夹中会出现垃圾回收日志,这样我们查看更加方便了。




对于垃圾回收 GC 的信息还可以通过--prof生成 V8 分析器输出来查看,命令:node --prof getMemory.js。当然此时生成的 v8.log 日志不具备可读性


对于该 v8.log 日志文件,可以使用--prof-process命令,也可以达到与linux-tick-processor工具类似的效果。


生成命令:node --prof-process v8.log > processed.txt


此命令会生成一个分析的 txt 文件:



发布于: 2021 年 11 月 15 日阅读数: 9
用户头像

空城机

关注

曾经沧海难为水,只是当时已惘然 2021.03.22 加入

业余作者,在线水文 主要干前端的活,业余会学学python 欢迎各位关注,互相学习,互相进步

评论

发布
暂无评论
NodeJs 深入浅出之旅:V8 内存分配🧙‍♂️