为了让前端工做更有效率,必须完全掌握一些必要的调试技巧。日常在开发Node应用的过程当中,最常使用的是本地调试,可是一旦你的代码到了生产环境,就必须采起其余策略进行追踪和解决问题。javascript
在编程领域,有一个专门的术语“Post-mortem debugging",它的意思是在程序奔溃后再进行的调试工做。对于Node程序来讲,若是你遇到了难以重现、线上环境没法调试等问题均可以采用这种方案进行操做。并且线上问题通常都是比较紧急的,因此咱们通常都但愿能最快定位到问题发生的代码。html
那么咱们具体要怎么作呢?下面举个简单的例子。前端
假设如今你有这样一段代码:java
const demo = (data) => {
const {id, profile} = person;
console.log(id);
console.log(profile.name);
}
demo({id: 1, profile: {age: 12}});
复制代码
运行后它会报错并退出。这时候你须要作的是收集奔溃信息并对其作分析。Core Dump就是这样用来记录程序运行信息的一种工具,它包含了程序运行过程当中的内存状态,调用栈等,能最真实地还原当时的“案发现场“。node
那么,在Node.js中咱们怎么得到Core Dump的文件呢?linux
首先,咱们先设置一下系统中的内核限制:git
ulimit -c unlimited
复制代码
而后你须要在启动应用的时候,使用--abort-on-uncaught-exception
这个flag来手动触发程序奔溃后写core文件的操做:github
node --abort-on-uncaught-exception app.js
复制代码
这样当程序忽然奔溃的时候,就会在linux或mac系统的/cores
目录下生成相似core.81371
这样的一个文件。这个文件就是咱们用来调试调查程序奔溃的核心。编程
若是你的程序正在执行过程当中,咱们也能够手动捕获core dump
文件,相似于实时检查,主要用于程序假死等状态。json
手动捕获的话须要使用Linux系统自带的 gcore 命令,具体用法是找出当前进程的pid(这里假设是123),而后执行命令:
gcore 123
复制代码
生成对应的core dump
文件。
另一种方式是采用lldb调试工具,mac系统下使用该命令进行安装:
brew install --with-lldb --with-toolchain llvm
复制代码
而后执行:
lldb --attach-pid <pid> -b -o 'process save-core' "core.<pid>"' 复制代码
这样就能在不重启程序的状况下导出特定进程的core dump
文件。
获得具体的core dump
文件后,咱们就要进入调试分析阶段了。
首先,须要使用选择顺手的分析工具。你能够选择mdb_v8或者llnode。这两个工具用起来都差很少。
这里以llnode为例,先介绍几个经常使用命令:
命令 | 意义 |
---|---|
v8 help | 查看帮助信息 |
v8 bt | get stack trace at crash 查看堆栈信息 |
v8 souce list | 显示stack frame的源码 |
v8 inspect | 查看对应地址的对象内容 |
frame select | 选择对应的stack frame |
在分析前,先须要用llnode加载core
文件:
llnode -c /cores/core.81371
复制代码
而后获取对应的堆栈信息:
// 查看堆栈信息
(llnode) v8 bt
// 根据堆栈信息找到可疑的地址,并查看对应的对象内容
(llnode) v8 inspect <address>
// 指定对应的stack frame
(llnode) frame select 6
// 查看源码
(llnode) v8 source list
复制代码
最后经过结合堆栈信息和源码就能找到错误发生的缘由了。
除了程序奔溃,有时候你还会发现应用随着运行时间增加,速度开始变慢。这可能就是内存泄漏捣的鬼。
好比下面这段代码:
const requests = new Map();
app.get("/", (req, res) => {
requests.set(req.id, req);
res.status(200).send("hello")
})
复制代码
一般来讲,内存泄漏容易发生在闭包等场景下。针对内存泄漏的调试,可使用以下命令:
node --trace_gc --trace_gc_verbose app.js
复制代码
启动应用后,经过压测工具运行以下命令:
ab -k -c200 -n10000000 http://localhost:3000
复制代码
能够看到随着程序的运行,内存使用愈来愈大。
另外,咱们还可使用heap snapshot
来获取快照信息:
process.on('SIGUSR2', () => {
const { writeHeapSnapshot } = require("v8");
console.log("Heap snapshot has written:", writeHeapSnapshot())
})
复制代码
在命令行中执行:
kill -SIGUSR2 <pid>
复制代码
就可以得到对应的快照文件,而后咱们可使用Chrome Devtools的Memory菜单加载对应的快照文件进行比对分析了。
若是是开发阶段,你也能够直接使用调试模式启动应用:
node --inspect app.js
复制代码
而后使用菜单Devtools > Memory > take heap snapshot得到快照文件。
经过比较两个不一样的内存快照,咱们能够很快找到内存增加最快的那个对象,而后进而分析对应的源码就能知道问题出在了哪里。
除了采用Chrome浏览器,在linux主机上,咱们还能使用万能的llnode调试器进行内存泄漏的分析。原理大体相同,也是经过分析core 文件,而后安装对象大小排序,针对可疑的对象进行源码查看。
(llnode) v8 findjsobjects
(llnode) v8 findjsinstances -d <Object>
(llnode) v8 inspect -m <address》
(llnode) v8 findrefs <address>
复制代码
另一种收集报告的策略是使用参数,适用于13.0以上版本:
node \
--experimental-report \
--diagnostic-report-uncaught-exception \
--diagnostic-report-on-fatalerror \
app.js
复制代码
这样在程序奔溃的时候,就可以获取到对应的报告。你还能够经过代码显式控制报告的输出文件名等:
process.report.writeReport('./foo.json');
复制代码
更多说明能够参考官方文档: nodejs.org/api/report.…
——转载请注明出处———
微信扫描二维码,关注个人公众号
最后,欢迎你们关注个人公众号,一块儿学习交流。
medium.com/netflix-tec… en.wikipedia.org/wiki/Debugg… www.bookstack.cn/read/node-i… github.com/bnoordhuis/…