@wa7son
Who am I?
• Thomas Watson
• Open Source developer at github.com/watson
• Principal Software Engineer at Elastic
• Node.js Core Member
• Tweets as @wa7son
Slide 5
Slide 5 text
@wa7son
Agenda
• Introduction to Post-Mortem Debugging
• What are core dumps
• Introduction to llnode
• Debugging crashes
• Debugging unresponsive processes
• Debugging memory leaks
Slide 6
Slide 6 text
@wa7son
Node.js Diagnostics
Working Group
github.com / nodejs / diagnostics
Slide 7
Slide 7 text
@wa7son
@wa7son
Post-Mortem Debugging
Slide 8
Slide 8 text
@wa7son
–Wikipedia
“Post-mortem debugging is debugging of the program
after it has already crashed.”
@wa7son
@wa7son
@wa7son
Source: Konstantin Lanzet
License: CC BY-SA 3.0
Slide 12
Slide 12 text
@wa7son
@wa7son
Source: Konstantin Lanzet
License: CC BY-SA 3.0
Slide 13
Slide 13 text
@wa7son
@wa7son
Slide 14
Slide 14 text
@wa7son
@wa7son
Slide 15
Slide 15 text
@wa7son
Slide 16
Slide 16 text
@wa7son
Processor registers
Program counter
System flags
Slide 17
Slide 17 text
@wa7son
Core Dump Formats
a.out Older versions of Unix
ELF Modern Linux, System V, Solaris, and BSD systems
Mach-O macOS, etc
Slide 18
Slide 18 text
@wa7son
Generating a Core Dump
ulimit -c unlimited
Maximum allowed
size of core dump
Slide 19
Slide 19 text
@wa7son
Generating a Core Dump
node --abort-on-uncaught-exception app.js
Slide 20
Slide 20 text
@wa7son
Generating a Core Dump
gcore
Generate a core dump
form a running process
on Linux
~/core.
Slide 21
Slide 21 text
@wa7son
Generating a Core Dump
lldb --attach-pid -b -o 'process save-core "core."'
Core dump
filename
Generate a core dump
form a running process
on macOS
Slide 22
Slide 22 text
@wa7son
Next Step: The Debugger
gdb, lldb, etc
Slide 23
Slide 23 text
@wa7son
LLDB
MacOS, iOS, Linux, FreeBSD, and Windows
as in DeBugger, not DataBase
@wa7son
Error: boom!
at /app/server.js:4:13
at /app/server.js:5:7
at /app/server.js:6:5
at processTicksAndRejections (internal/process/task_queues.js:79:9)
at process.runNextTicks [as _tickCallback] (internal/process/task_queues.js:56:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:871:11)
at internal/main/run_main_module.js:21:11
Slide 31
Slide 31 text
@wa7son
Reproducibility
fn3()
fn2()
fn1()
Slide 32
Slide 32 text
@wa7son
Demo Time!
Slide 33
Slide 33 text
@wa7son
npm install node-report
Slide 34
Slide 34 text
@wa7son
node —experimental-report app.js
Since Node.js v11.8.0
@wa7son
Recap 1/2
Production Server
• gcore
• lldb --attach-pid -b -o 'process save-core "core."'
Slide 41
Slide 41 text
@wa7son
Recap 2/2
Dev machine
• llnode node -c core
llnode
• v8 help Get help
• v8 bt Get stack trace at crash
• frame select 3 Select stack frame #3
• v8 source list Show source code at selected stack frame
• v8 inspect Inspect object at address
Slide 42
Slide 42 text
@wa7son
@wa7son
Memory Leaks
Slide 43
Slide 43 text
@wa7son
FATAL ERROR: CALL_AND_RETRY_2 Allocation failed
- process out of memory Abort trap: 6
Slide 44
Slide 44 text
@wa7son
What are Memory Leaks in JS?
Slide 45
Slide 45 text
@wa7son
What are Memory Leaks in JS?
No memory leak
(will be garbage collected)
@wa7son
Can this be improved?
• Convert a core dump to a heap snapshot
• Allow user to trigger a gc + heap snapshot from
outside the process
Slide 61
Slide 61 text
@wa7son
Heap Dump Diffing
Slide 62
Slide 62 text
@wa7son
Heap Dump Diffing
Find common
ancestor
Slide 63
Slide 63 text
@wa7son
Writing heap snapshots
process.on('SIGUSR2', () => {
const { writeHeapSnapshot } = require('v8')
if (global.gc) {
global.gc()
}
console.log('Heap snapshot written:’, writeHeapSnapshot())
})
node --expose-gc app.js
Returns name of file written
kill -SIGUSR2
(For now, works only on Node.js 11.13.0+)
Slide 64
Slide 64 text
@wa7son
Demo Time!
Slide 65
Slide 65 text
@wa7son
Recap
Dev machine
• llnode node -c core
llnode
• v8 help Get help
• v8 findjsobjects -d List all objects sorted by count
• v8 inspect Inspect object at address
• v8 findrefs Find all references to object at address