V8 内存限制
Node 与 V8
Node在JavaScript的执行上直接受益于V8,可以随着V8的升级就能享受到更好的性能或新的语言特性(如ES5和ES6)等,同时也受到V8的一些限制。
V8 的内存限制
在一般的后端开发语言中,在基本的内存使用上没有什么限制,然而在Node中通过JavaScript使用内存时就会发现只能使用部分内存(64位系统下约为1.4 GB,32位系统下约为0.7 GB)。
在这样的限制下,将会导致Node无法直接操作大内存对象,比如无法将一个2 GB的文件读入内存中进行字符串分析处理,即使物理内存有32 GB。这样在单个Node进程的情况下,计算机的内存资源无法得到充足的使用。
V8 的对象分配
在V8中,所有的JavaScript对象都是通过堆来进行分配的。Node提供了V8中内存使用量的查看方式,执行下面的代码,将得到输出的内存信息:
$ node
Welcome to Node.js v16.18.1.
Type ".help" for more information.
> process.memoryUsage();
{
rss: 27639808,
heapTotal: 5804032,
heapUsed: 4260752,
external: 991939,
arrayBuffers: 26876
}
在上述代码中,在memoryUsage()
方法返回的5个属性中,heapTotal
和heapUsed
是V8的堆内存使用情况。
rss
: "Resident Set Size",是进程在物理内存中占用的空间量,包括代码段、堆和栈的大小。
heapTotal
是已申请到的堆内存,heapUsed
是当前使用的量。
external
: 外部内存使用量,表示绑定到该进程的共享库或资源的内存使用量。
arrayBuffers
: 用于存储原始二进制数据的数组缓冲区的数量。用于处理大量数据,例如在处理图像、音频、视频或其他二进制文件时。
当我们在代码中声明变量并赋值时,所使用对象的内存就分配在堆中。如果已申请的堆空闲内存不够分配新的对象,将继续申请堆内存,直到堆的大小超过V8的限制为止。
至于V8为何要限制堆的大小,表层原因为V8最初为浏览器而设计,不太可能遇到用大量内存的场景。对于网页来说,V8的限制值已经绰绰有余。深层原因是V8的垃圾回收机制的限制。按官方的说法,以1.5 GB的垃圾回收堆内存为例,V8做一次小的垃圾回收需要50毫秒以上,做一次非增量式的垃圾回收甚至要1秒以上。这是垃圾回收中引起JavaScript线程暂停执行的时间,在这样的时间花销下,应用的性能和响应能力都会直线下降。
这个限制也不是不能打开,V8依然提供了选项让我们使用更多的内存。Node在启动时可以传递--max-old-space-size
或--max-new-space-size
来调整内存限制的大小
node --max-old-space-size=1700 test.js // 单位为MB
// 或者
node --max-new-space-size=1024 test.js // 单位为KB
上述参数在V8初始化时生效,一旦生效就不能再动态改变。如果遇到Node无法分配足够内存给JavaScript对象的情况,可以用这个办法来放宽V8默认的内存限制,避免在执行过程中稍微多用了一些内存就轻易崩溃。