前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >笔记:记一次解决V8使用内存超过默认限制

笔记:记一次解决V8使用内存超过默认限制

作者头像
Peter谭金杰
发布2020-05-09 17:34:07
3.3K0
发布2020-05-09 17:34:07
举报

起因:

混合TypeScript和javaScript开发,完美升级老项目,这个老项目是一个巨无霸项目,非常庞大,是集团公司的最核心项目


遇到问题:

webpack打包时候遇到

对于曾经开发过C++,addon的我,熟悉的味道,下面有一些v8的字符出现,感觉应该是v8层面出现了问题


报错解决:

任何报错,先看第一个报错,解决顶部的报错。


问题定位:

JS堆栈跟踪,javaScript heap out of memory ,内存不足


隐约记得,v8对使用内存的限制,64位系统是1.4G,32位系统是0.7G,Buffer属于C++层面,不会被限制。但是长度会被限制,当Buffer被创建时候就会被判断长度

代码语言:javascript
复制
https://github.com/nodejs/node/blob/master/lib/buffer.js#L90-L101

node.js官网对长度的文档描述:

这种简单问题不做阐述,继续


项目之前纯js开发,现在接入ts,为什么同样的电脑,之前可以运行,现在却内存不足?

答案:

  1. 首先要从内存回收说起,为什么要限制内存使用,因为1.4G普遍够用,再一个,内存回收是会阻塞主线程。300MB大概是0.5s,这里在我开发桌面端即时通讯应用时,经常会遇到这个问题。一个20万人的群,一直以1000条/秒的速度推送消息到桌面端,时间一长,Node接入主进程层面就不行了。CPU和内存占用会飙升,要做很多特殊优化处理
  2. 我在ts中配置允许使用js,那么意味着要增加一个编译ts成js的过程,这个编译过程肯定要占用大部分内存。所以之前纯js项目不会出现这个问题,
  3. 网上大部分都是手动更改webpack的源码文件,达到修改v8使用内存限制的目的,但是作为跨平台的产品来说,必须支持两点:工程化+自动化、可跨平台无感知的情况才能使用
  4. v8的内存回收机制影响,跟上面第二点搭配,当然,现在这套东西,已经被面试官问烂了(就跟考试让你背古诗一样),我面试是不会问这些无聊的问题。作为一个Node.js的深度使用者,我觉得是C++出生的人,可能会在Node.js走得更远,它更像是一个库,一个前端制作工具的库。如果要深入后端,走得更远,建议还是要学习java与c++
    • *

解决办法:

Node.js的8.0版本以上可以这样调整

代码语言:javascript
复制
export NODE_OPTIONS=--max_old_space_size=4096

也可以使用自动化、工程化配置插件

代码语言:javascript
复制
increase-memory-limit

由于一些部署服务器上的配置未知,在测试过后,我选择了后者,编写了新的构建命令,这样达到效果。


难道做API工程师,不可能的,我的原则,使用第三方库,框架必须看它的 源码实现,包括Node.js

increase-memory-limit

源码只有几十行代码

代码语言:javascript
复制
#!/usr/bin/env node
const path = require('path');
const glob = require('glob');
const fs = require('fs');

const maxOldSpaceSize = process.env.LIMIT || 10240;
const cwd = process.cwd() + path.sep;

glob(path.join(cwd, "node_modules", ".bin", "*"), function (err, files) {

  files.forEach(file => {
    // readFileSync will crash on non-files. Skip over these
    let stat = fs.lstatSync(fs.realpathSync(file));
    if (!stat.isFile()) {
      return;
    }
    if (file.indexOf('increase-memory-limit') >= 0) {
      return;
    }
    // build scripts will hand in LIMIT via cross-env
    // avoid updating it while we are running it
    if (file.indexOf('cross-env') >= 0) {
      return;
    }
    let contents = fs.readFileSync(file).toString();
    let lines = contents.split('\n')

    let patchedContents = "";

    for (var index = 0; index < lines.length; index++) {
      var line = lines[index];
      if (line.startsWith("if [") || line.startsWith("@IF") || line.indexOf ('has_node') !== -1) {
        patchedContents += line + "\n";
      } else {
        patchedContents += line.replace(/node(\.exe)?\b(?: \-\-max\-old\-space\-size\=[0-9]+)?/, `node$1 --max-old-space-size=${maxOldSpaceSize}`) + "\n";
      }
    }

    fs.writeFileSync(file, patchedContents);
    console.log(`'${file.replace(cwd, "")}'`, "written successfully.");
  });

});

它依赖glob这个库

代码语言:javascript
复制
https://www.npmjs.com/package/glob

首先读取LIMIT配置

然后拿到node启动的命令路径(配置path.sep针对跨平台,cwd返回的路径做处理分隔)

代码语言:javascript
复制
var glob = require("glob")

通过glob这库,传入路径和配置后,拿到包含文件数组,然后读取文件流信息并且toString()

最核心的源码文件就是下面这个

代码语言:javascript
复制
   patchedContents += line + "\n";
    } else {
      patchedContents += line.replace(/node(\.exe)?\b(?: \-\-max\-old\-space\-size\=[0-9]+)?/, `node$1 --max-old-space-size=${maxOldSpaceSize}`) + "\n";
    }
  }

  fs.writeFileSync(file, patchedContents);
  console.log(`'${file.replace(cwd, "")}'`, "written successfully.");

通过正则将读取的文件流信息,匹配相应的配置后,替换内容后同步写入(因为必须同步写入!!!否则项目无法启动,不能异步此处)


目前有一个系列写作计划,面试成长系列和踩坑成长系列同步进行,喜欢的话点个在看,关注下公众号:前端巅峰

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
即时通信 IM
即时通信 IM(Instant Messaging)基于腾讯二十余年的 IM 技术积累,支持Android、iOS、Mac、Windows、Web、H5、小程序平台且跨终端互通,低代码 UI 组件助您30分钟集成单聊、群聊、关系链、消息漫游、群组管理、资料管理、直播弹幕和内容审核等能力。适用于直播互动、电商带货、客服咨询、社交沟通、在线课程、企业办公、互动游戏、医疗健康等场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档