Garbage collected environments are magical trees you never have to cut yourself.
But this is not magic, and you are there to get insights on what is truly happening!
PART I - An application lifecycle
PART II - Understanding and analyzing
An application lifecycle
1 - Warming up
2 - Performing
3 - Leaking & underperforming
4 - Crashing
Understanding and experimenting
1 - Heap mechanics
2 - Retaining tree
3 - Garbage collector
4 - Analyzing
Code
Read-only
Map
Large objects
Old
New
V8 Ignition
V8 TurboFan
JavaScript
Bytecode
Machine code
Code
Heap
Handles
Program state
Reference
Internal pointer
Since objects move between heap spaces, they are wrapped in handles
root
ref 4 (weak)
ref 1
ref 2
ref 3
ref 5 (weak)
dead
dead
Experiment with Node 12
// node --expose-internals --expose-gc
const { internalBinding } = require('internal/test/binding');
const { WeakReference } = internalBinding('util');
let a = { foo: 'bar' };
const weakRef = new WeakReference(a);
weakRef.get() // a
a = null;
gc();
weakRef.get() // undefined
function main() {
const a = {};
const b = { a };
const c = [b];
const d = new Set();
d.add(c);
const e = new Map();
e.set(d, c);
const f = new WeakSet();
f.add(e);
const g = new WeakMap();
g.set(f, e);
return g;
}
const result = main();f
e
d
c
[d]
b
g
[f]
[0]
a
["a"]
result
0
1
2
3
4
Retain depth from g:
Allocations
Flip
to-space
from-space
to-space (previously from-space)
from-space (previously to-space)
Garbage scavenge collections
Main thread
GC threads (incl. main)
Any survivor is flagged and copied here
or copied to old space if flagged a second time
Next allocations
Old
Not yet discovered by GC
Some neighbors have not been processed
All neighbors have not been processed
GC will search objects from root
Reached => black, neighbors => grey
All reachable objects were processed
GC sweeps dead (white) objects
Page 1
Page 2
Page 3
MarkSweep = ~60% GC
MarkSweep = ~80% GC
Scavenger
MarkSweep
High marking / sweeping / compacting activity may mean
Its increase over time (even with activity decrease !) means
Obviously increasing old space size over time
High old space size may mean
Its increase over time (even with activity decrease !) means
C
B
D
A
Looking at 1 snapshot, we spot dominant objects
Their counts may be interpreted
GC + Snapshot
*
*
Cannot be collected
Can be collected
Warm up + perform N tasks
Study the snapshot !
A
B
A
B
A
B
A
C
A
C
Looking at snapshot 3 for objects allocated between snapshot 1 and 2, we spot objects that survived GC even after having assigned any resource in pools to other tasks: A, B, C
Snapshot 1
GC + Snapshot 2
GC + Snapshot 3
Warm up + perform N tasks
Perform N tasks
Perform N tasks again
Study snapshots !
A
A
A
B
C
| OPTION | MEANING |
|---|---|
| --trace-gc | show 1 line per GC pass |
| --trace-gc-ignore-scavenger | skip scavenger passes |
| --optimize-for-size | make GC less lazy |
| --max-old-space-size=X | sets old space size to X MB |
Few of them