Node 内存泄漏排查案例
背景
在阿里云上看到我运行了一段时间的程序,发现 memory 一项基本是在稳步提升,就知道有内存泄漏的情况出现。如下图

近三日从 35% 升到 40%,缓慢而坚定的提升。
代码
排查此问题需要分析其堆内存快照,当然我们不能直接使用线上机器调试。不幸的是测服机器在内网,和阿里云联不通,alinode 发挥不了作用。但所幸的是 V8 引擎提供了内部接口可以直接把堆中的JS对象导出来供开发者分析。我们采用heapdump这个模块,执行如下命令安装
$ npm install heapdump --save
"heapdump": "^0.3.15",
执行如下
const heapdump = require('heapdump');
heapdump.writeSnapshot(`./${Date.now()}.heapsnapshot`);
生成的文件如下
$ ll -lh
-rw-rw-r-- 1 souche souche 38M Nov 19 19:00 1574161221512.heapsnapshot
总之我在测服上定时每 2 小时打印堆栈快照。
总之,你可以使用 scp 命令把测服的代码导出到本地
# 传递单个文件
$ scp 【服务器用户名】@【服务器地址】:【服务器上存放文件的路径】【本地文件的路径】
# 例如
$ scp souche@172.11.xxx.xxx:/home/souche/app/egg-test/current/1574161221512.heapsnapshot /Users/dasouche/workspace/sc-node
# 传递文件夹
scp -r 【服务器用户名】@【服务器地址】:【服务器上存放文件的路径】【本地文件的路径】
分析步骤
打开 chrome-控制台-Memory-load

加载完后得到

简而言之,Shallow Size 就是对象自身被创建时所需要内存的大小,Retained Size 就是当把对象从支配树上拿掉,对象和它的下级节点一共能释放的内存大小。
其术语简介可参见:https://developers.google.com/web/tools/chrome-devtools/memory-problems/memory-101
分析过程
从线上机器导出两个堆文件,一个是10月30日打印的,一个是11月4日打印的,其内存上升了 100+ MB。
比对两个堆,把第二个堆文件的 Summary 切换成 Comparison,并按 Delta 倒叙排,发现增长最快的是 (concatenated string) 。其中有很多连接字符串,其中有大量的sql语句,并且有大量的schedule执行。

(constructor) 增长排第二,其中也见到不少 schedule,那我们可以确认就是 noticeJob.ts 这个定时器的问题。

本项目使用了 egg 作为框架,schedule 就是指定时触发的逻辑。联系代码我们发现在一个 5 秒触发一次的 schedule 里,里面不停的触发队列的 process 监听事件,猜测是 Queue.process 监听事件越绑越多的毛病,也导致里面的逻辑越触发越多。
这其实就是队列绑定监听事件的误用了。
// app/schedule/noticeJob.ts
'use strict';
import { Context } from 'egg';
import * as kue from 'kue';
module.exports = {
schedule: {
disable: false,
// 每五秒触发一次
cron: '*/5 * * * * *',
immediate: true,
type: 'worker',
},
async task(ctx: Context) {
const Queue = ctx.app.kue;
Queue.process('noticeCalling', async function(job, done) {
const { uid, rid, subId } = job.data;
await ctx.service.message.noticedCalling(uid, rid);
// done();
});
},
};
我们在测服注释掉这段定时器后,每隔一小时打印一次(因为测服无法连阿里云),观察一天,内存没有上升趋势,这很好。
-rw-rw-r-- 1 souche souche 38M Nov 24 11:24 1574565877609.heapsnapshot
-rw-rw-r-- 1 souche souche 37M Nov 24 12:24 1574569477611.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 24 13:24 1574573077611.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 24 14:24 1574576677613.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 24 15:24 1574580277614.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 24 16:24 1574583877614.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 24 17:24 1574587477616.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 24 18:24 1574591077616.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 24 19:24 1574594677616.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 24 20:24 1574598277618.heapsnapshot
-rw-rw-r-- 1 souche souche 37M Nov 24 21:24 1574601877620.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 24 22:24 1574605477621.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 24 23:24 1574609077622.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 25 00:24 1574612677622.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 25 01:24 1574616277622.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 25 02:24 1574619877623.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 25 03:24 1574623477624.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 25 04:24 1574627077626.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 25 05:24 1574630677627.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 25 06:24 1574634277627.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 25 07:24 1574637877628.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 25 08:24 1574641477629.heapsnapshot
-rw-rw-r-- 1 souche souche 38M Nov 25 09:24 1574645077630.heapsnapshot
-rw-rw-r-- 1 souche souche 39M Nov 25 10:24 1574648677630.heapsnapshot
-rw-rw-r-- 1 souche souche 39M Nov 25 11:24 1574652277632.heapsnapshot
解决方法
最后就在 app.ts 设置这个 process 的监听,移除 schedule 里的定时脚本
Node 内存泄漏排查案例的更多相关文章
- 轻松排查线上Node内存泄漏问题
I. 三种比较典型的内存泄漏 一. 闭包引用导致的泄漏 这段代码已经在很多讲解内存泄漏的地方引用了,非常经典,所以拿出来作为第一个例子,以下是泄漏代码: 'use strict'; const exp ...
- Chrome JS内存泄漏排查方法(Chrome Profiles)
原文网址:http://blog.csdn.net/kaitiren/article/details/19974269 JS内存泄漏排查方法(Chrome Profiles) Google Ch ...
- windows 下面的内存泄漏排查.
内存泄漏排查 一下本人只是简单的介绍一个实用, 如果读者很感兴趣, 可以查阅msdn自己去深入调查相关的API和原理. API 介绍 1. 马上打印泄漏信息:_CrtDumpMemoryLeaks() ...
- Java内存泄漏真实案例
内存泄漏:当不再需要一个对象时,垃圾收集器会回收它:如果不需要的对象一直在产生而不被收回,就称作“内存泄漏”. 以下为本人在工作中遇到的内存泄漏的案例: 1.对于大量的请求,使用了Executors. ...
- 填坑总结:python内存泄漏排查小技巧
摘要:最近服务遇到了内存泄漏问题,运维同学紧急呼叫解决,于是在解决问题之余也系统记录了下内存泄漏问题的常见解决思路. 本文分享自华为云社区<python内存泄漏排查小技巧>,作者:luti ...
- Netty堆外内存泄漏排查,这一篇全讲清楚了
上篇文章介绍了Netty内存模型原理,由于Netty在使用不当会导致堆外内存泄漏,网上关于这方面的资料比较少,所以写下这篇文章,专门介绍排查Netty堆外内存相关的知识点,诊断工具,以及排查思路提供参 ...
- JS内存泄漏排查方法——Chrome Profiles
一.概述 Google Chrome浏览器提供了非常强大的JS调试工具,Heap Profiling便是其中一个.Heap Profiling可以记录当前的堆内存(heap)快照,并生成对象的描述文件 ...
- 内存泄漏学习案例-1-ArrayList
解决 内存泄漏 于是赶快登陆探测服务器,首先是 top free df 三连,结果还真发现了些异常. 我们的探测进程 CPU 占用率特别高,达到了 900%. 我们的 Java 进程,并不做大量 CP ...
- Spring Boot引起的“堆外内存泄漏”排查及经验总结
小结: 检索词:C++内存分配器.jvm内存模型.gdb.内存泄露 https://tech.meituan.com/2019/01/03/spring-boot-native-memory-leak ...
随机推荐
- 挑战全网最幽默的Vuex系列教程:第一讲 Vuex到底是什么鬼
先说两句 官方已经有教程了,为什么还要写这个教程呢?说实话,还真不是我闲着蛋疼,官方的教程真的是太官方了,对于刚入门 Vuex 的童鞋来说,想必看官方的教程,很多地方就如同看圣经一样,比如「欧玛尼玛尼 ...
- AJ学IOS 之二维码学习,快速生成二维码
AJ分享,必须精品 二维码是一项项目中可能会用到的,iOS打开相机索取二维码的速度可不是Android能比的...(Android扫描二维码要来回来回晃...) 简单不多说,如何把一段资料(网址呀,字 ...
- AJ学IOS(49)多线程网络之线程的创建NSThreand
AJ分享,必须精品 一:NSThread的基本使用 1:创建和启动线程 一个NSThread对象就代表一条线程 创建.启动线程 NSThread *thread = [[NSThread alloc] ...
- 【转】Centos7启动网卡(获取ip地址)
这里之所以是查看下IP ,是我们后面要建一个Centos远程工具Xshell 连接Centos的时候,需要IP地址,所以我们这里先 学会查看虚拟机里的Centos7的IP地址 首先我们登录操作系统 用 ...
- python初学(三)
1.以软科中国最好大学排名为分析对象,基于requests库和bs4库编写爬虫程序,对2015年至2019年间的中国大学排名数据进行爬取,并按照排名先后顺序输出不同年份的前10位大学信息,要求对输出结 ...
- [总结]RMQ问题&ST算法
目录 一.ST算法 二.ST算法の具体实现 1. 初始化 2. 求出ST表 3. 询问 三.例题 例1:P3865 [模板]ST表 例2:P2880 [USACO07JAN]平衡的阵容Balanced ...
- Volatile不保证原子性(二)
Volatile不保证原子性 前言 通过前面对JMM的介绍,我们知道,各个线程对主内存中共享变量的操作都是各个线程各自拷贝到自己的工作内存进行操作后在写回到主内存中的. 这就可能存在一个线程AAA修改 ...
- day18作业
作业: # 1.编写课上讲解的有参装饰器准备明天默写 def auth(file_type): def outer(func): def inter(*args,**kwargs): if file_ ...
- 爬虫需要登陆怎么办?这份python登陆代码请收下
模拟登陆思路 通过selenium中的webdriver控制浏览器登录目标网站,然后获取模拟登陆需要的Cookie,再利用此Cookie来达到登录的效果.本次我们使用webdriver来驱动火狐浏览器 ...
- PHP 常用数组的具体运用?常用吗?
在 PHP 中,有三种类型的数组: 数值数组 - 带有数字 ID 键的数组 关联数组 - 带有指定的键的数组,每个键关联一个值 多维数组 - 包含一个或多个数组的数组 看具体实例: 创建数组 < ...