memory management

and hunting memory leaks

@naugtur, 2020
## Some history JavaScript didn't have leaking problem.

The app that tought me about memory leaks


There's a live-leaking demo at the end.
You can follow along if you checkout this:

github.com/naugtur/js-training-examples github.com/naugtur/node-example-heapdump

Garbage collection

What to collect??

Garbage collection

  1. Copy items that can be reached
  2. Swap
  3. Cleanup is done by not saving the rest
## It's more complicated than that - Incremental GC (FF16) - Generational GC (FF32) https://hacks.mozilla.org/2014/09/generational-garbage-collection-in-firefox/ - Scheduling GC (Chrome45) - Compacting GC (FF38) https://hacks.mozilla.org/2015/07/compacting-garbage-collection-in-spidermonkey/
## Generations - Young generation - Nursery (<1 gc old) - Intermediate (1gc old) - Old generation - (2+ gc old) Major GC - whole heap Minor GC - only young

Scheduling GC

Smarter garbage collection for smoother browsing and less memory usage, 2015/12/08
V8 garbage collection deep dive

Compacting GC

Compacting Garbage Collection in SpiderMonkey
More compacting GC

GC phases

marking -> sweeping -> compacting

And there's threads now...

but you're tired already, let's move on


used to be called Hidden classes

Hidden Classes and Inline Caching in V8 (2015)
Shapes and Inline Caches (2018)
Let's look at one picture from the article. image credit https://mathiasbynens.be/notes/shapes-ics

Latest V8 garbage collector (2019)


# Freeing memory

How it works

var aBoy = { name: "Johny" },
  aGirl = { name: "Sue" },
  anAnimal = { name: "Garfield" };

aBoy = null;
//Johny can now be garbage-collected
aGirl = { name: "Lucy" };
//Sue can now be garbage-collected

aGirl.ownsAnimal = anAnimal
//we have a new reference to Garfield
anAnimal = null;
//a reference is removed, but it was not the only one
//Garfield can't be garbage-collected

Popular misconceptions

  • no, delete keyword does not free memory
  • seriously, delete just slows you down (creates new Shape)
  • no, setting object to null doesn't remove the object, it changes the reference
## When a reference dies - Reference lifetime (var/let) - Functional scope - Function context is limited to used references now


What if I need thousands of objects for short periods of time? I'm implementing a minigun.

  • Create a set of empty objects you need
  • Make a getter that returns the least recently used one
  • Overwrite its fields with new values
  • Reuse the same N objects without ever causing garbage collection

This really is only useful for things like particle animation or UI rendering libraries

What's the problem?

## What's a leak?
### Leaving a reference to someting you expected to get garbage collected ```js const module = (function(){ const keptAsLongAsModuleLives = []; return { init:function(someObject){ keptAsLongAsModuleLives.push(someObject); //do stuff } } })(); ```
## What's not a leak, but could be worse? - unlimited in-memory cache of requests or sessions - asynchronous recursion gone wrong - reading files/uploads into memory instead of streaming - stream with broken backpressure - browser: canvas allocates all pixels on first use `rgba*width*height`
## Tools - heap snapshot + diff view - profiles -> allocation timeline - timeline -> memory - force GC - timeline -> trash icon - performance.memory (chrome) - process.memoryUsage() (Node.js) [Memory analysis vocabulary](https://developers.google.com/web/tools/chrome-devtools/memory-problems/memory-101)
# Training time