阅读 242

NodeJs深入浅出之旅:V8内存分配

V8内存分配

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

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

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

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

Node_查看内存大小.png

各内存的说明:

属性名说明
rss常驻集大小,是进程在主内存设备(即总分配内存的子集)中占用的空间量,包括所有 C++JavaScript 对象和代码。
heapTotalV8 的内存使用量,已申请到的内存
heapUsedV8 的内存使用量,当前已使用的内存
external绑定到 V8 管理的 JavaScript 对象的 C++ 对象的内存使用量。
arrayBuffersArrayBufferSharedArrayBuffer 分配的内存,包括所有 Node.js Buffer。 这也包含在 external 值中。 当 Node.js 被用作嵌入式库时,此值可能为 0,因为在这种情况下可能不会跟踪 ArrayBuffer 的分配

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

其中有三个值,分别是:

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

代码内存超出1.png

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

代码内存超出2.png

其中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的输出

代码内存超出3.png

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

代码内存超出4.png

注意: 在分配内存时需要注意系统空闲内存,不能超过系统的空闲内存。并且一般只能接受空闲内存的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) }`); 复制代码

代码内存超出5.png



查看垃圾回收日志

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

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

垃圾回收日志.png

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


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

垃圾回收日志1.png

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

垃圾回收日志2.png


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

垃圾回收日志3.png



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

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

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

prof内存1.png

prof内存2.png

这里就不按照《深入浅出node.js》一书中走了,书中是使用v8的linux-tick-processor工具 V8也提供了linux-tick-processor工具用于统计日志信息,该工具在Node的源码目录deps/v8/tools下可以找到,地址:github.com/nodejs/node… 垃圾回收日志4.png 可以将Node源码clone到本地:在源码目录deps/v8/tools找到linux-tick-processor工具,Windows下对应命令文件为windows-tick-processor.bat,将该目录添加到环境变量Path中,就可以直接调用。 Node源码.png


作者:空城机
链接:https://juejin.cn/post/7026735223597432862


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐