@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
Node.js Diagnostics
Working Group
github.com / nodejs / diagnostics
Slide 6
Slide 6 text
@wa7son
@wa7son
Post-Mortem Debugging
Slide 7
Slide 7 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 11
Slide 11 text
@wa7son
@wa7son
Source: Konstantin Lanzet
License: CC BY-SA 3.0
Slide 12
Slide 12 text
@wa7son
@wa7son
Slide 13
Slide 13 text
@wa7son
@wa7son
Slide 14
Slide 14 text
@wa7son
Slide 15
Slide 15 text
@wa7son
Processor registers
Program counter
System flags
Slide 16
Slide 16 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 17
Slide 17 text
@wa7son
Generating a Core Dump
ulimit -c unlimited
Maximum allowed
size of core dump
Slide 18
Slide 18 text
@wa7son
Generating a Core Dump
node --abort-on-uncaught-exception app.js
Slide 19
Slide 19 text
@wa7son
Generating a Core Dump
gcore
Generate a core dump
form a running process
on Linux
~/core.
Slide 20
Slide 20 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 21
Slide 21 text
@wa7son
Next Step: The Debugger
gdb, lldb, etc
Slide 22
Slide 22 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 30
Slide 30 text
@wa7son
$ node --abort-on-uncaught-exception server.js
Server is listening on port 3000
POST /signup
Uncaught TypeError: Cannot read property 'first' of undefined
FROM
onSave (/app/server.js:16:36)
Timeout._onTimeout (/app/server.js:31:5)
listOnTimeout (internal/timers.js:531:17)
processTimers (internal/timers.js:475:7)
[1] 10904 illegal hardware instruction (core dumped)
node --abort-on-uncaught-exception server.js
Slide 31
Slide 31 text
@wa7son
$ node --abort-on-uncaught-exception server.js
Server is listening on port 3000
POST /signup
Uncaught TypeError: Cannot read property 'first' of undefined
FROM
onSave (/app/server.js:16:36)
Timeout._onTimeout (/app/server.js:31:5)
listOnTimeout (internal/timers.js:531:17)
processTimers (internal/timers.js:475:7)
[1] 10904 illegal hardware instruction (core dumped)
node --abort-on-uncaught-exception server.js
Slide 32
Slide 32 text
@wa7son
$ node --abort-on-uncaught-exception server.js
Server is listening on port 3000
POST /signup
Uncaught TypeError: Cannot read property 'first' of undefined
FROM
onSave (/app/server.js:16:36)
Timeout._onTimeout (/app/server.js:31:5)
listOnTimeout (internal/timers.js:531:17)
processTimers (internal/timers.js:475:7)
[1] 10904 illegal hardware instruction (core dumped)
node --abort-on-uncaught-exception server.js
Slide 33
Slide 33 text
@wa7son
$ node --abort-on-uncaught-exception server.js
Server is listening on port 3000
POST /signup
Uncaught TypeError: Cannot read property 'first' of undefined
FROM
onSave (/app/server.js:16:36)
Timeout._onTimeout (/app/server.js:31:5)
listOnTimeout (internal/timers.js:531:17)
processTimers (internal/timers.js:475:7)
[1] 10904 illegal hardware instruction (core dumped)
node --abort-on-uncaught-exception server.js
/cores/core.10904
Slide 34
Slide 34 text
@wa7son
$ node --abort-on-uncaught-exception server.js
Server is listening on port 3000
POST /signup
Uncaught TypeError: Cannot read property 'first' of undefined
FROM
onSave (/app/server.js:16:36)
Timeout._onTimeout (/app/server.js:31:5)
listOnTimeout (internal/timers.js:531:17)
processTimers (internal/timers.js:475:7)
[1] 10904 illegal hardware instruction (core dumped)
node --abort-on-uncaught-exception server.js
Slide 35
Slide 35 text
@wa7son
$ node --abort-on-uncaught-exception server.js
Server is listening on port 3000
POST /signup
Uncaught TypeError: Cannot read property 'first' of undefined
FROM
onSave (/app/server.js:16:36)
Timeout._onTimeout (/app/server.js:31:5)
listOnTimeout (internal/timers.js:531:17)
processTimers (internal/timers.js:475:7)
[1] 10904 illegal hardware instruction (core dumped)
node --abort-on-uncaught-exception server.js
Slide 36
Slide 36 text
@wa7son
app.post('/signup', function singupRoute (req, res) {
save(req.body, function onSave (err, user) {
if (err) return res.status(500).send('Error: ' + err.message)
res.end('Welcome ' + user.name.first)
})
})
Cannot read property 'first' of undefined
Slide 37
Slide 37 text
@wa7son
Demo Time!
Slide 38
Slide 38 text
@wa7son
@wa7son
Unresponsive Process
Slide 39
Slide 39 text
@wa7son
What is your program
doing right now?
Slide 40
Slide 40 text
@wa7son
const stringify = require('./lib/stringify')
// Turn this:
// { foo: 1, bar: 2 }
// Into this:
// { foo: "1", bar: "2" }
console.log(stringify({ foo: 1, bar: 2 }))
Slide 41
Slide 41 text
@wa7son
Demo Time!
Slide 42
Slide 42 text
@wa7son
Alternative:
CPU Profiling
Slide 43
Slide 43 text
@wa7son
Recap 1/2
Production Server
• gcore
• lldb --attach-pid -b -o 'process save-core "core."'
Slide 44
Slide 44 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 45
Slide 45 text
@wa7son
@wa7son
Memory Leaks
Slide 46
Slide 46 text
@wa7son
FATAL ERROR: CALL_AND_RETRY_2 Allocation failed
- process out of memory Abort trap: 6
Slide 47
Slide 47 text
@wa7son
What are Memory Leaks in JS?
Slide 48
Slide 48 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 64
Slide 64 text
@wa7son
Heap Dump Diffing
Slide 65
Slide 65 text
@wa7son
Heap Dump Diffing
Find common
ancestor
Slide 66
Slide 66 text
@wa7son
Writing heap snapshots
process.on('SIGUSR2', () => {
const { writeHeapSnapshot } = require('v8')
console.log('Heap snapshot written:’, writeHeapSnapshot())
})
Returns name of file written
kill -SIGUSR2
(For now, works only on Node.js 11.13.0+)
Slide 67
Slide 67 text
@wa7son
Load two
heap snapshots
Make a diff
Sort by Delta
Slide 68
Slide 68 text
@wa7son
Slide 69
Slide 69 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