↑开局一张图,故事全靠编↑
从一次宕机说起
这是一个很狗血的故事,故事的开头是一个项目,这个项目十分草率,草率到什么程度?没有设计稿,没有文档,需求全靠口口相传,当然最草率的是交给了我,我简单列了下需求:
官网的形式,主要介绍公司某些业务
要能发文章
尽管很简单的需求,对于水得一匹的我来说,简直是“难于上青天”,三大件 (html,css,javascript) 我样样精通个 P,网站部署我也只略知一二,代码编水平更是不学无术。作为 Copy 工程师,遇到需求我便开始了 copy 之路,先 github 溜达了一圈,找了几个满足需求的项目,最终对比了一下,选择了一个名叫 iBlog2 的项目 – 基于 Node.js 的个人开源博客系统。您没看错,就是一个博客系统!这跟官网有个毛关系?这个宕机又有个毛关系?我想说的是,经过 copy 然后小改之后,iBlog2 摇身一变就成了能发布文章的官网项目,就是这么简单粗暴,就是这么不学无术(温馨提示:少壮不努力,老大偷代码)。
这个 3 年之前的项目,在现在看来的确是有些陈旧,但作者 @eshengsky 依旧坚持不懈的在更新维护, 而对于我而言,只是为了完成能发文章的官网,所以只关注文章是如何发布和储存的,恰恰是因为我关注的面窄,忽略了部署和部署之后可能会遇到的各种问题,比如 window 下 pm2 可能出现问题、比如这次的 JavaScript heap out of memory。当然并不是人家开源项目有问题,而是实际部署的时候压根没按照作者的文档来,如果按照文档,我应该用 pm2 部署,或者启用 redis,或者使用 Noginx, 或者使用本机的 MongoDB 服务,然而,这一切,我只是在我们那个服务器新开了个端口,然后直接 npm run dev 就开始跑在线上了,所以呢,这么“锈”的操作,不宕机才是天理难容,印象中 JavaScript heap out of memory 遇到两次了,才两三个月啊!
检索 JavaScript heap out of memory
通常遇到问题,我首选的解决流程是打开 Chrome– 输入关键词 – 搜索 – 浏览 –copy– 尝试,好像从来没有去思考过产生问题的根源,甚至都没有去记录这个问题以及解决的方案,导致再遇到同样的坑,又掉进去了,然后又是一通检索尝试等操作,这也是我从业这么多年来,一直没养成的习惯,也是这么多年一直没成长的某一个小的原因,“少抱怨,多思考,未来会更美好”,而我一直以反面教材在诠释这个金句。
通常来说,只要您的关键词够准确,您就能通过 google 搜索找到尽可能满意的解决方案,如果连关键词都没把握好,我想就算请教的大牛,也不一定能有效的回答,当然思否和 Stack Overflow 都可能有填您那个坑的“铁楸”,还有一个阵地就是 github。
通常来说,程序报错一般都有详细的报错说明,比如哪一行、出了什么错、出错明细等,就比如文章开头的那张报错图,我找到了其他用户遇到的一模一样的问题:
<— Last few GCs —>
[8138:0x102801600] 145460 ms: Mark-sweep 1265.6 (1301.6) -> 1265.6 (1308.6) MB, 289.8 / 0.0 ms allocation failure GC in old space requested
[8138:0x102801600] 145740 ms: Mark-sweep 1265.6 (1308.6) -> 1265.6 (1277.6) MB, 280.6 / 0.0 ms last resort gc
[8138:0x102801600] 146035 ms: Mark-sweep 1265.6 (1277.6) -> 1265.6 (1277.6) MB, 295.0 / 0.0 ms last resort gc
<— JS stacktrace —>
==== JS stack trace =========================================
Security context: 0x39c891dc0d31 <JS Object>
1: DoJoin(aka DoJoin) [native array.js:~97] [pc=0x5d1facabad4](this=0x39c891d04311 <undefined>,q=0x5a024bf3be1 <JS Array[2241635]>,r=2241635,F=0x39c891d043b1 <true>,B=0x39c891ddafe9 <String[1]\: \n>,A=0x39c891d04421 <false>)
2: Join(aka Join) [native array.js:~122] [pc=0x5d1fb5cde96](this=0x39c891d04311 <undefined>,q=0x5a024bf3be1 <JS Array[2241635]>,r=2241635,B=0x39c891ddafe9 <String[1…
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed – JavaScript heap out of memory
1: node::Abort() [/Users/erossignon/.nvm/versions/node/v7.2.0/bin/node]
2: node::FatalException(v8::Isolate*, v8::Local<v8::Value>, v8::Local<v8::Message>) [/Users/erossignon/.nvm/versions/node/v7.2.0/bin/node]
3: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [/Users/erossignon/.nvm/versions/node/v7.2.0/bin/node]
4: v8::internal::Factory::NewRawTwoByteString(int, v8::internal::PretenureFlag) [/Users/erossignon/.nvm/versions/node/v7.2.0/bin/node]
5: v8::internal::Runtime_StringBuilderJoin(int, v8::internal::Object**, v8::internal::Isolate*) [/Users/erossignon/.nvm/versions/node/v7.2.0/bin/node]
6: 0x5d1faa063a7
Abort trap: 6
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed – JavaScript heap out of memory 这个是报错的关键词,通常也是我们检索的关键词,至于为什么会导致这个错误,报错信息就显示 JavaScript 堆内存不足,信息中也显示了最近几次 GC 的详情,GC(Garbage collection)是垃圾回收机制,具体可以阅读一下 JavaScript 内存泄漏教程。经过初步了解,就是我们的应用内容泄露的,通常治标不治本的解决方案就是加大 Node.js 运行时内存中保留的“未使用”空间量:
node –max-old-space-size=4096 yourFile.js
JavaScript heap out of memory 的原因及解决方案
Node 运行时 V8 内存的限制
Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine.,一般情况下,Node 在运行时只能使用到系统的一部分内存,64 位系统下约为 1.4GB,32 位系统下约为 0.7GB【有待考证,出处 @JerryC】。当 GC 时,如果老生区大小超过设定的值时,就会报错。一般解决方案:在启动 node 程序的时候,可以传递两个参数来调整内存限制的大小,解除默认的限制如
node –max-nex-space-size=1024 app.js // 单位为 KB
node –max-old-space-size=2000 app.js // 单位为 MB
实践中的解决可能会有以下操作:
项目运行 wepack 打包时出现内存泄漏问题经常抛异常
set NODE_ENV=production && node –max_old_space_size=2048 node_modules/webpack/bin/webpack.js –config webpack.production.config.js
yarn serve – JavaScript heap out of memory crash
“dev”: “npx –max_old_space_size=4096 vue-cli-service serve”
代码问题
除了环境问题,最关键的问题就是代码本身存在问题,毕竟上面的方法治标不治本,要根治这个毛病,可能需要审视代码,先监测到内存泄漏的原因,把这部分代码找出优化。一般是无限制增长的数组、无限制设置属性和值、大循环等【出处:@林小新】。这部分由于 Copy 攻城狮并为深入,可以参考如何定位 Node.js 的内存泄漏、node 内存泄漏以及定位