在阿里云上看到我运行了一段时间的程序,发现 memory 一项基本是在稳步提高,就知道有内存泄漏的状况出现。以下图node
近三日从 35% 升到 40%,缓慢而坚决的提高。web
排查此问题须要分析其堆内存快照,固然咱们不能直接使用线上机器调试。不幸的是测服机器在内网,和阿里云联不通,alinode 发挥不了做用。但所幸的是 V8 引擎提供了内部接口能够直接把堆中的JS对象导出来供开发者分析。咱们采用heapdump这个模块,执行以下命令安装sql
$ npm install heapdump --save "heapdump": "^0.3.15",
执行以下chrome
const heapdump = require('heapdump'); heapdump.writeSnapshot(`./${Date.now()}.heapsnapshot`);
生成的文件以下npm
$ ll -lh -rw-rw-r-- 1 souche souche 38M Nov 19 19:00 1574161221512.heapsnapshot
总之我在测服上定时每 2 小时打印堆栈快照。bash
总之,你可使用 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-loadapp
加载完后获得框架
简而言之,Shallow Size 就是对象自身被建立时所须要内存的大小,Retained Size 就是当把对象从支配树上拿掉,对象和它的下级节点一共能释放的内存大小。async
其术语简介可参见: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 里的定时脚本