一、现象

1. 如下报错
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
1: node::Abort() [/usr/local/bin/node]
2: node::OnFatalError(char const*, char const*) [/usr/local/bin/node]
3: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [/usr/local/bin/node]
4: v8::internal::Factory::NewFixedArray(int, v8::internal::PretenureFlag) [/usr/local/bin/node]
5: v8::internal::OrderedHashTable<v8::internal::OrderedHashMap, 2>::Rehash(v8::internal::Handle<v8::internal::OrderedHashMap>, int) [/usr/local/bin/node]
6: v8::internal::Runtime_MapGrow(int, v8::internal::Object**, v8::internal::Isolate*) [/usr/local/bin/node]
7: 0x2ecd2d1042fd
8: 0x2ecd2d1b251e
2.在linux服务器上输入top命令,发现该进程memery占用居高不下。

二、内存泄漏介绍

由上述问题可以确认,该node服务内存泄露. Node.js 进程的内存管理,都是有 V8 自动处理的,包括内存分配和释放。那么 V8 什么时候会将内存释放呢?

在 V8 内部,会为程序中的所有变量构建一个图,来表示变量间的关联关系,当变量从根节点无法触达时,就意味着这个变量不会再被使用了,就是可以回收的了。 而这个回收是一个过程性的,从快速 GC 到 最后的 Full GC,是需要一段时间的。 另外,Full GC 是有触发阈值的,所以可能会出现内存长期占用在一个高值,也可以算是一种内存泄漏,可以从《一次 Node.js 应用内存暴涨分析》中找到例子。还有一种就是引用不释放,导致无法进入 GC 环节,并且一直产生新的占用,这一般会发生在 Javascript 层面。

所以,定位内存泄漏问题,一般方案就是找那些不被使用又不会被释放的变量,处理了这些变量,问题一般就可以解决了。如果是 Node.js 底层变量不释放,除了提交 issue 等待解决外,只能通过优化启动参数来解决。

三、问题定位

1、看代码,代码里面是否存在闭包或者变量声明或者引用不当的地方。
2、是否引用node-canvas 或者echart等大型消耗cpu内存资源等依赖包
3、借助工具来分析,比如heapdump + chrome浏览器 memery分析工具

四、问题修复以heapdump为例,分析并修复内存泄漏的问题(基于express项目)。

1、项目根目录下安装heapdump
// node version > v0.8
npm install heapdump // Or, if you are running node.js v0.6 or v0.8:
npm install heapdump@0.1.0
2、入口文件引入这个heapdump
// express中,在app.js中加入
const heapdump = require('heapdump');
3、重启该express服务,top(mac 上通过 top -pid xxx 查看) 命令查看linux占用情况:,

并发起少数几次请求后,输入如下命令,生成heap快照文件,记作name1

kill -USR2 <pid>
4、模拟批量服务请求

由于我这个是可以提供给web调用的接口,因此用一个抓包工具charles(或者其他模拟请求工具都行),重复发1000次请求,在用top命令查看该进程memery占用情况。发现问题可以重现了。同时输入如下命令:

// in UNIX platforms
kill -USR2 <pid>
// 执行上述命令,会生成一下heap快照的文件,记作name2
 
5、拷贝name1、name2文件到本地,并在chrome浏览器中打开分析;

6 、经过上述对比分析,可以得知代码存在的问题,然后作出相关优化。

比如,我这里是用到了node-canvas 和 Echart,最后发现这两个对象引用后一直没有内内存回收,导致内存溢出。代码层面做如下优化:

    stage.destroy();
chart.dispose();
chart = null;
stage = null;

然后,启动服务,模拟1000次请求,结果发现内存占用比之前少了很多,基本上不会出现内存溢出的问题了。

express 内存溢出问题分析定位的更多相关文章

  1. jvm内存溢出问题的定位方法

    jvm内存溢出问题的定位方法 今天给大家带来JVM体验之内存溢出问题的定位方法. 废话不多说直接开始: 一.Java堆溢出 测试代码如下: import java.util.*; public cla ...

  2. 记一次内存溢出的分析经历——thrift带给我的痛orz

    说在前面的话 朋友,你经历过部署好的服务突然内存溢出吗? 你经历过没有看过Java虚拟机,来解决内存溢出的痛苦吗? 你经历过一个BUG,百思不得其解,头发一根一根脱落的烦恼吗? 我知道,你有过! 但是 ...

  3. 记一次内存溢出的分析经历——使用thrift

    背景: 有一个项目做一个系统,分客户端和服务端,客户端用c++写的,用来收集信息然后传给服务端(客户端的数量还是比较多的,正常的有几千个), 服务端用Java写的(带管理页面),属于RPC模式,中间的 ...

  4. android 内存溢出问题分析

      最近的项目中,内存一直再增长,但是不知道是什么问题,导致内存溢出,在网上看到了这么一篇关于内存分析与管理的文章,解决了部分问题,感觉这篇文 章还不错,就转帖到我的blog上了,希望对大家有所帮助. ...

  5. Java常见内存溢出异常分析(OutOfMemoryError)

    原文转载自:http://my.oschina.net/sunchp/blog/369412 1.背景知识 1).JVM体系结构 2).JVM运行时数据区 JVM内存结构的相关可以参考: http:/ ...

  6. JVM:Java常见内存溢出异常分析

    转载自:http://www.importnew.com/14604.html Java虚拟机规范规定JVM的内存分为了好几块,比如堆,栈,程序计数器,方法区等,而Hotspot jvm的实现中,将堆 ...

  7. tomcat 内存溢出原因分析及解决

    一.错误提示:java.lang.OutOfMemoryError: Java heap space [原因分析] tomcat默认可以使用内存为128MB,在较大型的应用项目中不足以满足运行要求,在 ...

  8. (一)深入java虚拟机之内存溢出与分析

    一.内存溢出程序 public class Test { public static void main(String[] args) { List<User> userList=new ...

  9. 本地模拟内存溢出并分析Dump文件

    java Dump文件分析 前言 dump文件是java虚拟机内存在某一时间点的快照文件,一般是.hprof文件,下面自己模拟一下本地内存溢出,生成dump文件,然后通过mat工具分析的过程. 配置虚 ...

随机推荐

  1. 前端表单提交数据~php获取表单内容

    上图代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  2. Win7下,nginx默认80端口被System占用,造成nginx启动报错

    在win7 32位旗舰版下,启动1.0.8版本nginx,显示如下错误: 2012/04/02 13:55:59 [emerg] 7864#2376: bind() to 0.0.0.0:80 fai ...

  3. MongoDB中的读写锁

    1. MongoDB 使用的锁 MongoDB 使用的是“readers-writer”锁, 可以支持并发但有很大的局限性当一个读锁存在,许多读操作可以使用这把锁,然而, 当一个写锁的存在,一个单一的 ...

  4. C#动态给Word文档填充内容

    //filePath:word文档的路径:strOld:需要替换的内容:strNew:替换的新内容: //注意:strOld中的字符数量要与新的strNew中的一一对应 public static v ...

  5. Linq to SQL -- 入门篇

    一.什么是Linq Linq是语言集成查询(Language Integrated Query)的简称,是visual Studio 2008和.NET Framework 3.5版本中一项突破性的创 ...

  6. windows 杀死进程

    查看所有进程: tasklist 查看某一个进程: tasklist | findstr python 杀死进程:taskkill /F /PID python.exe 查看端口占用情况:netsta ...

  7. flink入门:01 构建简单运行程序

    1. mac平台安装flink(默认最新版) brew install apache-flink 安装结果: Version 1.7.1, commit ID: 89eafb4 2. jdk版本,我尝 ...

  8. JavaScript数组方法--filter、find、findIndex

    继续数组方法,今天应该到filter了. filter:filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素. 使用: var words = ['spray', 'lim ...

  9. mysql修改root密码及修改密码过程中报错的解决方案

    参考网站: https://www.linuxidc.com/Linux/2018-05/152586.htmhttps://www.cnblogs.com/wangbaobao/p/7087032. ...

  10. Java架构师技能发展脑图

    图中还有好多东西不会,先把图保存好,逐项击破