Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Leak Hunting: Finding and debugging a memory le...

Leak Hunting: Finding and debugging a memory leak in Node.js

Presented: NodeSummit 2018

Giovanny Gongora

July 23, 2018
Tweet

More Decks by Giovanny Gongora

Other Decks in Technology

Transcript

  1. J U LY 2 3 , 2 0 1 8

    C O N F I D E N T I A L Leak Hunting Finding and debugging a memory leak in Node.js
  2. © 2018 NodeSource C O N F I D E

    N T I A L We do a lot of Node! (crazy right?) • N|Solid • NCM • ~18 companies trust our support team for inquiries and problems around node. • …expect more
  3. C O N F I D E N T I

    A L © 2018 NodeSource Developers/Companies (not all) don’t consider how difficult could be to track and fix a memory leak until it happens
  4. C O N F I D E N T I

    A L © 2018 NodeSource Developers/Companies (not all) don’t consider how difficult could be to track and fix a memory leak until it happens … a day before of a new version to be released
  5. C O N F I D E N T I

    A L © 2018 NodeSource Developers/Companies (not all) don’t consider how difficult could be to track and fix a memory leak until it happens … after a new cool feature is pushed
  6. C O N F I D E N T I

    A L © 2018 NodeSource Developers/Companies (not all) don’t consider how difficult could be to track and fix a memory leak until it happens … in production on Friday night
  7. C O N F I D E N T I

    A L © 2018 NodeSource Developers/Companies (not all) don’t consider how difficult could be to track and fix a memory leak until it happens … prod gets more client request than dev tests
  8. © 2018 NodeSource C O N F I D E

    N T I A L Types of production issues
  9. © 2018 NodeSource C O N F I D E

    N T I A L Runtime performance: • The website/app is slow. • Not giving a great/fast experience to the user.
  10. © 2018 NodeSource C O N F I D E

    N T I A L Things you can do on Runtime performance issues: • --perf-basic-prof-only-functions. • A system tool like Perf Events in Linux. • Spare the traces that are really important in your situation.
  11. © 2018 NodeSource C O N F I D E

    N T I A L Runtime crashes: • Uptime is critical. • Not easily to reproduce. • Resume the process asap.
  12. © 2018 NodeSource C O N F I D E

    N T I A L Things you can do on Runtime crashes: • --abort-on-uncaught-exception. • Use some system tooling llbd, gbd, mdb.
  13. © 2018 NodeSource C O N F I D E

    N T I A L Memory leaks: • This will be our focus today.
  14. © 2018 NodeSource C O N F I D E

    N T I A L Quick brief around Memory in Node.js
  15. © 2018 NodeSource C O N F I D E

    N T I A L Garbage Collection Every program that consumes memory requires a mechanism for reserving and freeing space.
  16. © 2018 NodeSource C O N F I D E

    N T I A L How GC works: • Root R
  17. © 2018 NodeSource C O N F I D E

    N T I A L How GC works: • Root. • Object. R O O O O
  18. © 2018 NodeSource C O N F I D E

    N T I A L How GC works: • Root. • Object. • Primitives. R O O O O P P
  19. © 2018 NodeSource C O N F I D E

    N T I A L How GC works: • Root • Object. • Primitives. • Non referenced object. R O O O O P P O P
  20. © 2018 NodeSource C O N F I D E

    N T I A L Memory scheme (v8): • Resident Set R E S ID E N T SE T
  21. © 2018 NodeSource C O N F I D E

    N T I A L Memory scheme (v8): • Resident Set • Code Segment R E S ID E N T SE T CO DE S E GM E NT
  22. © 2018 NodeSource C O N F I D E

    N T I A L Memory scheme (v8): • Resident Set • Code Segment • Stack R E S ID E N T SE T CO DE S E GM E NT STACK
  23. © 2018 NodeSource C O N F I D E

    N T I A L Memory scheme (v8): • Resident Set • Code Segment • Stack • Heap R E S ID E N T SE T CO DE S E GM E NT STACK H E AP
  24. © 2018 NodeSource C O N F I D E

    N T I A L Memory scheme (v8): • Resident Set • Code Segment • Stack • Heap • Used heap R E S ID E N T SE T CO DE S E GM E NT STACK H E AP RSS 
 H E APTOTA L 
 H E AP US E D
 E XT E R N AL
  25. © 2018 NodeSource C O N F I D E

    N T I A L Relation between GC and a memory leak? • Impossible to remove non referenced data. • Portion of memory allocated not released when no longer needed.
  26. © 2018 NodeSource C O N F I D E

    N T I A L Memory Leak causes: • Registered event handlers • Function closures • Leaking connections
  27. © 2018 NodeSource C O N F I D E

    N T I A L Process to investigate an issue: • Think and construct an hypothesis • Collect data • Analyze the data (duh) • Draw a conclusion • Repeat (profit?)
  28. © 2018 NodeSource C O N F I D E

    N T I A L Strategy for Memory Leaks detection: • Inspect objects for more context. • Look for weird objects on heap • Growing object counts are likely leaking • Walk reverse references to find the root object • Compare object counts !important
  29. © 2018 NodeSource C O N F I D E

    N T I A L Let’s do it!
  30. © 2018 NodeSource C O N F I D E

    N T I A L Node.js Using V8 Inspector & Chrome Dev Tools • Run your node process with --inspect • Check chrome://inspect • Run it!
  31. © 2018 NodeSource C O N F I D E

    N T I A L Taking Snapshots of the V8 Memory • Check the Memory tab • Take heap snapshot • Profit!
  32. © 2018 NodeSource C O N F I D E

    N T I A L What is happening? • On the first snapshot, there are already/almost 5MB allocated before any request is processed. • Memory keeps growing while the server is running • Exactly # Date objects and # Objects have been allocated between the two load sessions.
  33. © 2018 NodeSource C O N F I D E

    N T I A L Possible solution: • Reduce Date • The solution for this example is to store the logs not in memory, but on the filesystem
  34. © 2018 NodeSource C O N F I D E

    N T I A L • As you can see, the memory growth is far slower! • This said, the API takes more time to respond. Reading and writing to the disk comes with a cost, so do other API calls or database requests.
  35. © 2018 NodeSource C O N F I D E

    N T I A L Last considerations?
  36. © 2018 NodeSource C O N F I D E

    N T I A L Name you functions
  37. © 2018 NodeSource C O N F I D E

    N T I A L • Var test = function () {}
  38. © 2018 NodeSource C O N F I D E

    N T I A L • Var test = function () {} • test.protory.biz = function () {}
  39. © 2018 NodeSource C O N F I D E

    N T I A L • Var test = function () {} • test.protory.biz = function () {} • fs.writeFile(chunck, function(err) {})
  40. © 2018 NodeSource C O N F I D E

    N T I A L • Var test = function () {} • test.protory.biz = function () {} • fs.writeFile(chunck, function(err) {}) • What about arrow functions?
  41. © 2018 NodeSource C O N F I D E

    N T I A L Don’t block on I/O
  42. © 2018 NodeSource C O N F I D E

    N T I A L I/O operations are… • Expensive. • A waste of resources if your program is unable to do other work. • Usually a hidden operation.
  43. © 2018 NodeSource C O N F I D E

    N T I A L Blocking the Event Loop • Totally possible • Happens more times we want them to happen • Iterations and complex calculations would prevent the process from handling other events
  44. © 2018 NodeSource C O N F I D E

    N T I A L Succeed doing I/O operations: • Choose asynchronous over synchronous • Opt for parallel I/O wherever possible • Don't hog the JavaScript thread with long-running calculations and iterations
  45. © 2018 NodeSource C O N F I D E

    N T I A L Async FTW! Modern applications spend most of their time waiting for I/O
  46. © 2018 NodeSource C O N F I D E

    N T I A L • Better work scheduling • Reduces thread CPU overhead • V8 can only do one thing at a time • Spend as little time in V8 as possible
  47. © 2018 NodeSource C O N F I D E

    N T I A L What we can learn from this: • A running Node.js application uses asynchronous I/O for performance. • Node.js runs JavaScript in a single thread. Each JavaScript function runs until completion. • I/O operations can be performed synchronously, but will occupy the main thread and prevent events from being processed
  48. C O N F I D E N T I

    A L Thank you. Giovanny Gongora [email protected] @Gioyik