一、文章背景
由于接手的公司项目属于大型项目,功能模块一百多个,所以在本地运行的时候node堆内存溢出的情况频繁出现。导致日常开发受阻,且开发体验极差。
二、原因
1、node内存限制问题
V8引擎最初是为浏览器设计的,一个标签页就是一个V8引擎实例,所以不太可能遇到需要很大内存的场景。其次V8引擎的垃圾回收机制决定了内存越大执行一次垃圾回收所需的时间也就越长,而执行垃圾回收机制时Javascript线程会暂停执行,因此综合而言默认V8引擎内存进行限制便是最好的方案。
一般情况下x64的环境中node的默认可使用堆内存大小为1.4G左右,当运行的项目占用堆内存超过1.4G时,node就会抛出异常,终止运行,同时告知堆内存溢出。
2、代码逻辑问题
本文章的重点不在如果分析、解决代码中导致内存泄漏的问题,所以便粗略的讲一下。一般引起内存溢出的情况是全局变量定义太多,大量的使用闭包并且没有在使用完毕后进行销毁,存在大量缓存等原因。
三、解决方案
根据上面的分析,我们主要针对解除v8引擎内存的限制进行探寻解决方案。
- 修改内存指令:( V8中内存分为新生代内存和老生代内存。新生代内存主要用于存储存活时间短的对象,而老生代内存主要用于存储存活时间长的对象。)
- 新生代内存修改指令:
--max-new-space-size=1024
(单位是KB) - 老生代内存修改指令:
--max-old-space-size=4096
(单位是MB)
- 新生代内存修改指令:
- 而堆内存泄漏绝大数情况都是发生在老生代内存中,因此我们只需要关注老生代内存修改指令即可
- 针对不同的情况的修改方式:
- 单文件执行时:
node --max-old-space-size=xxxx test.js
- vue或者react项目中:
- 在项目中或者全局中安装插件:
cross-env
和increase-memory-limit
- 在项目package.json文件的scripts中添加命令:
"edit-memory-limit" : "cross-env LIMIT=8192 increase-memory-limit"
- 最后在控制台中执行
npm run edit-memory-limit
- 但此时运行环境可能V8内存此时还并没有针对此项目进行临时解除内存限制,我们还需要讲node_modules文件中的.bin目录下所有的cmd文件中的
“%_prog%”
修改成%_prog%
- 此时原因会内存溢出的项目便会正常运行了。不过要注意的是上面的8192是可认为修改的,单位是MB,并且不可大于本机实际物理内存。
- 在项目中或者全局中安装插件:
- 单文件执行时:
三、进阶
到这里本文要达到的目的已经实现,但是可能有小伙伴该说了,好麻烦呀,下载安装npm包,再修改package.json文件,最后还要执行命令后去修改.bin目录下所有的cmd文件,太繁琐了。
没关系,我们也可以不用这么繁琐。
非侵入性自动化处理内存限制解决方案
- 工具:
@ylzq/eml
- 命令:
npm i @ylzq/eml -g
- 执行:
eml set <size>
,size为要设定的内存大小,单位为MB。然后剩下的问题就不用操心了,该工具会帮助你解决剩下的操作。
四、总结
V8引擎默认设定的内存满足浏览器的使用,但是面对node服务端逐级的力不从心,所以如何修改内存限制,如何方便的修改内存限制便成为了日常开发中不常用但会遇到的问题解决能力。当然解决内存泄漏问题除了修改内存限制,排查、分析和解决项目中代码逻辑问题也是必不可少的一环,毕竟再大的内存也经不住上不封顶的缓存,海量的用完不置空的闭包,以及海量的全局变量等…