一 、现象描述
由于项目在运行或者项目打包时突然停止build项目或者崩溃掉,工作台会频繁报出内存溢出报出:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
二、为什么Nodejs内存会溢出?
要明白node内存溢出的原因,先了解一下node内存机制。下面简单介绍node机制和原理(介绍node原理较浅浅,详细内容请看:Nodejs官网)
1、V8的内存机制
- 内存的分配
一切JavaScript对象都用堆来存储!!!
- 当我们在代码中声明变量并赋值时,使用对象的内存就分配在堆中。
- 如果已申请的对空闲内存不够分配新的对象,将会继续申请堆内存,直到堆的大小超过V8内存的限制为止。
- 这也是注意到为什么要一直少用全局作用域,也是为了高效使用内存,并且和垃圾回收机制紧密联系,详细可以看一下大佬讲解==》Node高效使用内存
- 内存的限制
Node内存其实并不是和后端语言一样,对内存使用没有多少限制,只是在Node使用内存中,只能使用系统物理内存的一部分,64位系统下约为1.4GB,32位系统下约为0.7GB,这也是归结于Node使用了运行在浏览器的V8引擎。
- 为什么内存限制
内存限制主要原因是v8的垃圾回收制度。1.5GB内存做一次小的回收需要50MS,做一次非增量性回收需要1S以上,并且这会使JS线程暂停。因此限制内存。
- 不受内存限制的特例
在介绍不受内存限制前需要了解一下node内存分为两类:
- V8内存: JavaScript内置对象(String、Array、Date、Boolean、Number、Math等对象),运行时使用V8内存。
- 系统内存: Buffer是一个Node.js的扩展对象,使用底层的系统内存,不占用V8内存空间。与之相关的文件系统fs和流Stream流操作,都不会占用V8内存。
- 修改内存限制大小
// 单位为KB 新生代
node --max-nex-space-size=1024 index.js
// 单位为MB 老生代
node --max-old-space-size=1700 index.js
`
2. V8的垃圾回收机制简说
1、V8的垃圾回收策略主要基于 「分代式垃圾回收机制」,基于这个机制,V8把内存分为 「新生代(New Space)」 和 「老生代 (Old Space)」。
所以知道为什么新生代中的对象为存活时间较短的对象分配的容量少,老生代中的对象为存活时间较长或常驻内存的对象而分配的容量多。
- 为什么要分成新老两代?
垃圾回收算法有很多种,但是并没有一种是胜任所有的场景,在实际的应用中,需要根据对象的生存周期长短不一,而使用不同的算法,已达到最好的效果。在V8中,按对象的存活时间将内存的垃圾回收进行不同的分代,然后分别对不同的内存施以更高效的算法。
三、node溢出解决方案
说了那么多,也大概明白node内存溢出前因后果啦,针对node溢出解决方案很多,下面简单说我的解决方案:
- 在package.json的scripts中加上配置:
node指令可以查看内存就可知道自己是否申请到扩容,
D:\vanke\gjwy-front>node
> process.memoryUsage() // 查看node内存的指令
{ rss: 24428544, // 进程的常驻内存
heapTotal: 7684096, // 已申请到的堆内存
heapUsed: 5096712, // 当前使用的堆内存
external: 9039 }
- 新增依赖包
npm install --save-dev increase-memory-limit
执行npm run fix-memory-limit(只需执行一次即可)
重启项目即可
四、总结
1、加强node深入研究,在了解过程也对间接地学习相关联知识,但还需要花很多时间去考究和学习。
2、 简单了解V8引擎的前生今世的的由来, 详细请点击 V8引擎