在阿里雲上看到我運行了一段時間的程序,發現 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 裏的定時腳本