$30 off During Our Annual Pro Sale. View Details »

Understanding Memory Behavior on NodeJS

Understanding Memory Behavior on NodeJS

The idea is to talk about memory in nodejs (V8 behavior), describing common and more complex leaks. Presenting how to debug, detect and solve problems with memory.

Understanding concepts like heap/stack, mark-and-sweep, garbage, memory allocation, cyclic reference, memory life cycle, V8's stop-the-world and more. In addition to showing real cases of memory leaks from globo.com.

Raphael Amorim

September 29, 2017
Tweet

More Decks by Raphael Amorim

Other Decks in Programming

Transcript

  1. ~
    Understanding
    Memory Behavior
    on NodeJS
    The memory concept in 

    JavaScript engines
    @raphamundi

    View Slide

  2. Raphael
    Amorim
    This guy seems like a nice person, but
    he doesn’t. Seriously. He likes topics
    related to JavaScript, Python, Clojure,
    WebGL, Algorithms and sometimes force
    some git push.

    Working most part of his time in useless
    globo.com •
    js foundation/jQuery member •
    Mozillian •
    Metido a besta •
    @raphamundi
    This guy seems like a
    he doesn’t. Seriously.
    related to JavaScript,
    WebGL, Algorithms and
    some git push.

    Working most part of h
    open source projects.
    some git push.

    Working most part of his
    open source projects.

    View Slide

  3. talentos.globo.com

    View Slide

  4. [Question] Would you board a plane

    programmed by JavaScript?

    View Slide

  5. [Question] Would you board a plane

    programmed by JavaScript?
    54% Yes
    32% No
    14% I don’t know

    View Slide

  6. Motivations (?)

    View Slide

  7. Developers (not all)
    don’t considers (or just doesn’t know)
    how tricky can be memory management
    in Nodejs.

    View Slide

  8. INTRO

    View Slide

  9. Computer memory
    is any physical device
    capable of storing information
    temporarily or permanently.

    View Slide

  10. Computer memory
    is any physical device
    capable of storing information
    temporarily or permanently.

    View Slide

  11. the ‘ is 

    from 

    other ‼

    View Slide

  12. Memory is Limited

    View Slide

  13. NODEJS

    View Slide

  14. View Slide

  15. Initially created for Google Chrome,
    but it can also be used as a standalone.

    View Slide

  16. 83%* of all
    INTERPRETERS
    AREN’T IN
    JAVASCRIPT
    *invented number

    View Slide

  17. View Slide

  18. NodeJS is a C++
    program controlled
    via V8
    *https://github.com/v8/v8/wiki/Getting%20Started%20with%20Embedding

    View Slide

  19. Dynamic memory allocation

    View Slide

  20. Dynamic memory allocation
    Weakly typed

    View Slide

  21. Dynamic memory allocation
    Weakly typed
    "V8's stop-the-world"

    View Slide

  22. Dynamic memory allocation
    Weakly typed
    "V8's stop-the-world"
    "generational"

    View Slide

  23. V8:
    garbage collection

    View Slide

  24. Every program that consumes memory requires
    a mechanism for reserving and freeing space.

    View Slide

  25. In C and C++, this is accomplished by
    malloc() and free()
    Every program that consumes memory requires
    a mechanism for reserving and freeing space.

    View Slide

  26. char * buffer;
    buffer = (char*) malloc (42);
    // Do something with buffer
    free (buffer);

    View Slide

  27. char * buffer;
    buffer = (char*) malloc (42);
    // Do something with buffer
    free (buffer);
    What this means?

    View Slide

  28. In this case (C++) the
    programmer is responsible for
    freeing heap memory that is
    no longer required.

    View Slide

  29. Programmers make mistakes.

    View Slide

  30. /* Allocate 30 bytes to house a string */
    char* str = new char [30];
    /* Clear those 30 bytes and make str point nowhere */
    delete [] str;

    View Slide

  31. /* Allocate 30 bytes to house a string */
    char* str = new char [30];
    /*
    Give str another memory address with
    the first one gone forever
    */
    str = new char [60];
    delete [] str;

    View Slide

  32. Fail to remove data that can
    not be referenced.

    View Slide

  33. When a portion of memory
    allocated for certain
    operation is not released
    when it's no longer needed.

    View Slide

  34. Fail to remove data that can not be
    referenced.
    When a portion of memory allocated for
    certain operation is not released when
    it is no longer needed.
    It’s a 

    Memory Leak

    View Slide

  35. Garbage collection is double-edged sword

    View Slide

  36. positive side:
    languages that use it become more
    simple.

    View Slide

  37. negative side:
    no control of memory.

    View Slide

  38. ECMAScript specification doesn't
    expose any interface to
    garbage collector.

    View Slide

  39. Performance of garbage collected languages is
    not strictly better or worse
    than languages without managed memory!

    View Slide

  40. V8:
    memory scheme

    View Slide

  41. Resident Set
    ~ V8 uses a scheme similar to the
    Java Virtual Machine and divides
    the memory into segments ~

    View Slide

  42. Resident Set
    Code Segment
    Stack
    Heap
    Used Heap

    View Slide

  43. ~Code Segment~
    The actual code
    being executed

    View Slide

  44. [|||||]
    Stack Variable

    View Slide

  45. char *buff[500]

    View Slide

  46. Contains all value types with pointers referencing
    objects on the heap.

    View Slide

  47. [|||||]
    Heap Variable

    View Slide

  48. char *buff = (char *)malloc(500)

    View Slide

  49. A memory segment dedicated to storing reference types
    like objects, strings and closures.

    View Slide

  50. process.memoryUsage()
    *https://nodejs.org/api/process.html#process_process_memoryusage

    View Slide

  51. console.log(process.memoryUsage());
    {
    rss: 4935680,
    heapTotal: 1826816,
    heapUsed: 650472,
    external: 49879
    }

    View Slide

  52. console.log(process.memoryUsage());
    {
    rss: 4935680,
    heapTotal: 1826816,
    heapUsed: 650472,
    external: 49879
    }
    rss refer to resident set size.

    View Slide

  53. console.log(process.memoryUsage());
    {
    rss: 4935680,
    heapTotal: 1826816,
    heapUsed: 650472,
    external: 49879
    }
    heapTotal and heapUsed refer to V8's memory usage.

    View Slide

  54. console.log(process.memoryUsage());
    {
    rss: 4935680,
    heapTotal: 1826816,
    heapUsed: 650472,
    external: 49879
    }
    external refers to the memory usage of C++ objects
    bound to JavaScript objects managed by V8.

    View Slide

  55. Terms:
    generationals

    View Slide

  56. View Slide

  57. How
    Memory Allocation
    works in
    Nodejs

    View Slide

  58. // allocation for Number
    var num = 42;
    // allocation for String
    var str = “my string”;

    View Slide

  59. // allocation for Number
    var num = 42;
    // allocation for String
    var str = “my string”;
    Rvalue
    Lvalue

    View Slide

  60. // each element is a not named reference
    var arr = [1, null, "ABC"]

    View Slide

  61. // each element is a not named reference
    var arr = [1, null, "ABC"]
    *In-Object slack tracking

    View Slide

  62. In-Object slack tracking

    View Slide

  63. // each element is a not named reference
    var arr = [1, null, "ABC"]
    *In-Object slack tracking
    *overflow array

    View Slide

  64. // callable - executable object
    function fun(a) { return a + 10 }

    View Slide

  65. // functions with expressions do object allocation
    myElement.addEventListener(‘click’, () => {

    myElement.style.opacity = 0

    }, false)

    View Slide

  66. Cyclic reference

    View Slide

  67. // cycle allocation
    var a = {}
    var b = {}
    a.c = b
    b.d = a

    View Slide

  68. Hightlight:
    Garbage
    Collector
    Sample

    View Slide

  69. > var myObject = {

    person: {
    name: "raphael",
    age: 21,
    }

    }

    View Slide

  70. var myObject = {

    person: {
    name: "raphael",
    age: 21,
    }

    }
    > var anotherObject = myObject

    View Slide

  71. var myObject = {

    person: {
    name: "raphael",
    age: 21,
    }

    }
    var anotherObject = myObject
    > myObject = 1

    View Slide

  72. > var yetAnotherObject = anotherObject.person
    person: {
    name: "raphael",
    age: 21,
    }

    }
    var anotherObject = myObject
    myObject = 1

    View Slide

  73. > anotherObject = “some-random-string”
    var yetAnotherObject = anotherObject.person
    }

    }
    var anotherObject = myObject
    myObject = 1

    View Slide

  74. > yetAnotherObject = null
    anotherObject = “some-random-string”
    var yetAnotherObject = anotherObject.person
    var anotherObject = myObject
    myObject = 1

    View Slide

  75. Hightlight:
    Building
    A Leak

    View Slide

  76. easy, right?

    View Slide

  77. function LeakingClass() {
    // do-nothing
    }

    View Slide

  78. function LeakingClass() {
    // do-nothing
    }
    var leaks = []

    View Slide

  79. function LeakingClass() {
    // do-nothing
    }
    var leaks = []
    setInterval(function() {
    for (var i = 0; i < 100; i++) {
    leaks.push(new LeakingClass)
    }
    console.error('Leaks: %d', leaks.length)
    }, 1000)

    View Slide

  80. it’s so fun, let’s create another!

    View Slide

  81. const developer = {
    name: “amorim”,
    company: “globocom”
    }
    doWork(() => {
    const data = developer.name
    // doing a bunch of work
    })

    View Slide

  82. one more!

    View Slide

  83. const http = require(‘http')
    const server = http.createServer((req, res) => {
    for (var i=0; i<1000; i++) {
    server.on('request', function LeakFunc() {})
    }
    res.end(‘Hello, The Conf!’)
    }).listen(8585, ‘127.0.0.1')
    server.setMaxListeners(0)
    console.log(`Server running at 127.0.0.1:8585/.
    Process PID: ${process.pid}`)

    View Slide

  84. Hightlight:
    Debugging
    A Leak

    View Slide

  85. let’s get back to the leak examples

    View Slide

  86. function LeakingClass() {
    // do-nothing
    }
    var leaks = []
    setInterval(function() {
    for (var i = 0; i < 100; i++) {
    leaks.push(new LeakingClass)
    }
    console.error('Leaks: %d', leaks.length)
    }, 1000)
    leak.js

    View Slide

  87. node --inspect leak.js

    View Slide

  88. View Slide

  89. View Slide

  90. View Slide

  91. Hint:
    You can also send the SIGUSR1 signal
    to an existing node process to enable
    the inspect mode as you need it.

    View Slide

  92. Hint2:
    It's important to use named constructors,
    otherwise the heap snapshots will
    not produce useful outputs for you.

    View Slide

  93. const http = require(‘http')
    const server = http.createServer((req, res) => {
    for (var i=0; i<1000; i++) {
    server.on('request', function LeakFunc() {})
    }
    res.end(‘Hello, The Conf!’)
    }).listen(8585, ‘127.0.0.1')
    server.setMaxListeners(0)
    console.log(`Server running at 127.0.0.1:8585/.
    Process PID: ${process.pid}`)
    server-leak.js

    View Slide

  94. npm i memwatch-next
    or
    npm i node-memwatch

    View Slide

  95. View Slide

  96. › ab -n 1000 -c 100 http://127.0.0.1:8585/

    View Slide

  97. View Slide

  98. View Slide

  99. There’s a lot of tools to help you!
    - node-memwatch
    - node-heapdump
    - node-inspector
    - nodetime
    - v8-profiler
    - memwatch-next
    - ...

    View Slide

  100. const developer = {
    name: “amorim”,
    company: “globocom”
    }
    doWork(() => {
    const data = developer.name
    // doing a bunch of work
    })
    closure-leak.js

    View Slide

  101. const developer = {
    name: “amorim”,
    company: “globocom”
    }
    doWork(() => {
    const data = developer.name
    // doing a bunch of work
    developer = null
    })

    View Slide

  102. Hightlight:
    Wrap up

    View Slide

  103. "Even valid code can cause memory leaks."

    View Slide

  104. theThing = null

    View Slide

  105. References:
    - https://blog.codeship.com/understanding-garbage-
    collection-in-node-js
    - https://speakerdeck.com/pantuza/memory-leak-em-
    javascript
    - https://medium.com/@_lrlna/garbage-collection-in-v8-an-
    illustrated-guide-d24a952ee3b8
    - http://jayconrod.com/posts/55/a-tour-of-v8-garbage-
    collection
    - https://github.com/v8/v8/wiki

    View Slide

  106. References:
    - https://stackoverflow.com/questions/19550253/memory-
    leaks-and-closures-in-javascript-when-and-why
    - https://www.nearform.com/blog/self-detect-memory-leak-
    node/
    - https://github.com/felixge/node-memory-leak-tutorial
    - https://stackoverflow.com/questions/6261201/how-to-
    find-memory-leak-in-a-c-code-project

    View Slide

  107. Thank
    You
    @raphamundi

    View Slide