一招轻松解决node内存溢出问题

简介: 一招轻松解决node内存溢出问题

node启动项目造成内存溢出的解决办法

我们在使用node启动项目的时在项目较大的时候,可能会造成内存溢出。为什么会造成内存溢出呢?
要回答上面这个问题,我们要了解node中是如何分配内存的。
Node中通过JavaScript使用内存时只能使用部分内存(64位系统:1.4 GB, 32位系统:0.7 GB)
如果前端项目比较大,Webpack编译时就会占用很多的系统资源,
此时一旦超出了V8引擎对Node默认的内存限制大小时,就会产生内存溢出的错误。
在终端我们就会看见如下关键报错信息: 
<--- JS stacktrace --->
<--- Last few GCs --->
这些都表明内存溢出了。

详细报错信息

<--- Last few GCs --->
[130124:0000021FC62BC9D0]     1795 ms: Scavenge 1762.7 (1796.8) -> 1762.6 (1796.8) MB, 34.4 / 0.0 ms 
 (average mu = 1.000, current mu = 1.000) allocation failure
[130124:0000021FC62BC9D0]     2409 ms: Mark-sweep 1922.7 (1956.8) -> 1922.0 (1956.1) MB, 487.4 / 0.0 ms
  (+ 38.4 ms in 10 steps since start of marking, biggest step 5.0 ms, walltime since start of marking 2053 ms)
 (average mu = 1.000, current mu = 1.000)
<--- JS stacktrace --->
FATAL ERROR: MarkCompactCollector: young object promotion failed Allocation failed - JavaScript heap out of memory

解决内存溢出的办法

我们知道了内存溢出的原因:现在我们扩展内存就可以了.
# linux & mac下面
export NODE_OPTIONS=--max_old_space_size=8096
# windows 下面 [window推荐使用这个] 你直接在命令行窗口CMD 中输入如下命令就ok了。
set NODE_OPTIONS=--max_old_space_size=8096 
# 使用cross-env解决mac 与 windows 的差异
npm install --save-dev cross-env # 安装
cross-env NODE_OPTIONS=--max_old_space_size=8096

了解几个属性

创建 look.js文件
let neiCun = process.memoryUsage();
console.log('内存大小:',neiCun); 
输出
内存大小: {
  rss: 19619840,
  heapTotal: 4481024,
  heapUsed: 2817824,
  external: 941362,
  arrayBuffers: 9898
}
属性名           说明
rss             常驻集大小,是进程在主内存设备(即总分配内存的子集)中占用的空间量,包括所有 C++ 和 JavaScript 对象和代码。
heapTotal       V8 的内存使用量,已申请到的内存 单位是:B
heapUsed        V8 的内存使用量,当前已使用的内存 单位是:B
external        绑定到 V8 管理的 JavaScript 对象的 C++ 对象的内存使用量。
arrayBuffers    为 ArrayBuffer 和 SharedArrayBuffer 分配的内存,包括所有 Node.js Buffer。 这也包含在 external 值中。 
                当 Node.js 被用作嵌入式库时,此值可能为 0,因为在这种情况下可能不会跟踪 ArrayBuffer 的分配
小知识:在浏览器的控制台中输入 window.performance 命令也可以查看内存

jsHeapSizeLimit totalJSHeapSize usedJSHeapSize 的讲解

在控制台输入    window.performance
出现如下一部分的属性
memory:{
    jsHeapSizeLimit: 2172649472,
    totalJSHeapSize: 215072162,
    usedJSHeapSize: 211564498
}
这个几个属性的意思
jsHeapSizeLimit: 2172649472    totalJSHeapSize: 629811769    usedJSHeapSize: 624884689 
jsHeapSizeLimit  代表内存大小限制, 2172649472/1024/1024 ≈ 2072M,也就是2G,这也佐证了新的V8已经将内存从1.4G限制提升上来了。
totalJSHeapSize 代表可使用内存  629811769/1024/1024 ≈ 600M
usedJSHeapSize是JavaScript对象占用的内存,不能大于totalJSHeapSize,如果大于,可能出现了内存泄漏

变量何时销毁

内存中主要存储变量等数据:
局部变量当程序执行结束,且没有引用时就会消失。
全局对象回始终存活到程序结束运行

使用--max-old-space-size进行手动内存分配

function getMemory(n) {
    let memory = process.memoryUsage();
    console.log(`申请到内存:${(memory.heapTotal/1024/1024).toFixed(1)}MB`);
    console.log(`已使用内存:${(memory.heapUsed/1024/1024).toFixed(1)}MB`);
    console.log(`--------------------循环了${n}次`)
}
// 每次都会接受一个大数组
function useMem(){
    let size = 20 * 1024 * 1024;
    let arr = new Array(size);
    return arr;
}
// 全局变量
let total = [];
for (let j = 0; j < 30; j++) {
    getMemory(j+1);
    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=8096 这可以将老生代内存空间扩充到 8096 MB。

简单介绍一下 V8 引擎的垃圾回收机制

v8 引擎将内存分为了新生代和老生代。
新创建的对象或者只经历过一次的垃圾回收的对象被称为新生代。
经历过多次垃圾回收的对象被称为老生代。
新生的对象容易早死,老生代活得更久
新生代被分为 From 和 To 两个空间。
To 一般是闲置的,当 From 空间满了的时候会执行 Scavenge 算法进行垃圾回收。
这个算法分为三步:
1.首先检查 From 空间的存活对象,
如果判断这个存活对象是否满足晋升到老生代的条件,
满足条件则晋升到老生代,如果不满足条件则移动 To 空间。
2.如果对象不存活,则释放对象的空间。
3.最后将 From 空间和 To 空间角色进行交换

V8 新生代对象晋升到老生代有两个条件:

1.第一个是判断对象否已经经过一次 Scavenge 回收。
若经历过,则将该对象从 From 空间复制到老生代中;
若没有经历,则复制到 To 空间。
2.第二个是 To 空间的内存使用占比是否超过限制。
当对象从 From 空间复制到 To 空间时,若 To 空间使用超过 25%,
则对象直接晋升到老生代中。
设置 25% 的原因主要是因为算法结束后,
两个空间结束后会交换位置,如果 To 空间的内存太小,会影响后续的内存分配。

使用--max-old-space-size命令来扩充堆内存空间

执行 node --max-old-space-size=8096 .\look.js

在分配内存时不能超过系统的空闲内存

注意: 在分配内存时需要注意系统空闲内存,不能超过系统的空闲内存。并且一般只能接受空闲内存的75%。可以使用导入os来进行查看。
const os = require('os');
let totalmem = os.totalmem();  // 以整数形式返回系统内存总量(以字节为单位B)
let freemem = os.freemem();  // 以整数形式返回空闲的系统内存量(以字节为单位B)。
console.log(`系统总内存:${ (totalmem/1024/1024).toFixed(1) },系统空闲内存:${ (freemem/1024/1024).toFixed(1) }`)

遇见问题,这是你成长的机会,如果你能够解决,这就是收获。

相关文章
|
4月前
|
存储 Kubernetes 容器
【CKA模拟题】查找集群中使用内存最高的node节点
【CKA模拟题】查找集群中使用内存最高的node节点
49 1
|
19天前
|
Web App开发 存储 监控
Node.js中的内存泄漏
【8月更文挑战第31天】Node.js中的内存泄漏
36 1
|
1月前
|
搜索推荐 Java API
Electron V8排查问题之分析 node-memwatch 提供的堆内存差异信息来定位内存泄漏对象如何解决
Electron V8排查问题之分析 node-memwatch 提供的堆内存差异信息来定位内存泄漏对象如何解决
38 0
|
2月前
|
移动开发 运维 JavaScript
阿里云云效操作报错合集之遇到Node.js的内存溢出问题,该怎么办
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
存储 Prometheus Cloud Native
FinOPS之 节点内存态统计和计算Node-metrics
董江,容器技术布道者及实践者,中国移动高级系统架构专家,曾担任华为云核心网技术专家,CloudNative社区核心成员,KubeServiceStack社区发起者,Prometheus社区PMC,Knative Committer,Grafana社区Contributer。 欢迎关注:https://kubeservice.cn/
FinOPS之 节点内存态统计和计算Node-metrics
|
11月前
|
JavaScript API
使用 Node.js Stream API 减少服务器端内存消耗的一个具体例子
使用 Node.js Stream API 减少服务器端内存消耗的一个具体例子
如何检测node中是否存在内存泄露的隐患
如何检测node中是否存在内存泄露的隐患
53 0
|
存储 缓存 监控
重学Node系列03-内存管理及GC算法
Node内存控制 这是重新阅读《深入浅出NodeJS》的相关笔记,这次阅读发现自己依旧收获很多,而第一次阅读的东西也差不多忘记完了,所以想着这次过一遍脑子,用自己的理解输出一下,方便记忆以及以后回忆...
122 0
|
缓存 算法 Java
Elasticesearch内存详解(五)——Node Query Cache
接收Elasticesearch内存中的Node Query Cache
528 0
|
JavaScript 前端开发 开发者
Node.js 应用故障排查手册 —— 冗余配置传递引发的内存溢出
前面一小节我们以一个真实的压测案例来给大家讲解如何利用 [Node.js 性能平台](https://www.aliyun.com/product/nodejs) 生成的 CPU Profile 分析来进行压测时的性能调优。
1499 0