Table of Contents generated with DocToc
- Theory
- Tools
- Resources
- memory held by object itself
- arrays and strings may have significant shallow size
- memory that is freed once object itself is deleted due to it becoming unreachable from GC roots
- held by object implicitly
- made up of handles that are created when making a reference from native code to a JS object ouside of v8
- found in heap snapshot under GC roots > Handle scope and GC roots > Global handles
- internal GC roots are window global object and DOM tree
- primitives are leafs or terminating nodes
- strings stored in VM heap or externally (accessible via wrapper object)
- VM heap is heap dedicated to JS objects and managed byt v8 gargabe collector
- native objects stored outside of VM heap, not managed by v8 garbage collector and are accessed via JS wrapper object
- cons string object created by concatenating strings, consists of pairs of strings that are only joined as needed
- arrays objects with numeric keys, used to store large amount of data, i.e. hashtables (key-value-pair sets) are backed by arrays
- map object describing object kind and layout
- native objects group is made up from objects holding mutual references to each other
- not represented in JS heap -> have zero size
- wrapper objects created instead, each holding reference to corresponding native object
- object group holds wrapper objects creating a cycle
- GC releases object groups whose wrapper objects aren't referenced, but holding on to single wrapper will hold whole group of associated wrappers
- shown at the bottom inside heap snapshots UI
- nodes/objects labelled by name of constructor function used to build them
- edges labelled using property names
- retaining path is any path from GC roots to an object, if such a path doesn't exist the object is unreachable and subject to being garbage collected
- can be seen in Dominators view
- tree structure in which each object has one dominator
- if dominator is deleted the dominated node is no longer reachable from GC root
- node d dominates a node n if every path from the start node to n must go through d
read Understanding the Unicorn
- logical errors in JS that keep references to objects that aren't needed anymore
- number one error: event listeners that haven't been cleaned up correctly
- this causes an object to be considered live by the GC and thus prevents it from being reclaimed
- not available to use with Node.js ATM
- memory usage overview over time
- can be used to identify memory leaks and/or performance bottlenecks caused by a busy garbage collector
- top band shows events over time that caused memory usage to be affected
- Records shows these events in detail and allows drilling into them to see a stack trace
- GC events are included as well (not shown in the picture)
- Memory shows memory usages colored coded
- Details (on the right) shows how long each event or each separate function call took
- the heapdump module supports Node.js
v0.6-v0.10
require('heapdump')
in your module and cause it to write a heap snapshot viakill -USR2 <pid>
- before a heap dump is taken, v8 performs two GC
cycles
(also for Node.js
v0.10
)in order to remove collectable objects - objects in the resulting heapdump are still referenced and thus couldn't be garbage collected
Although as mentioned above before a heapdump is taken all garbage is collected, I found that manually triggering garbage collection and forcing the GC to compact yields better results. The reason for this is unclear to me.
Add the below snippet to your code which will only activate if you are exposing the garbage collector:
// shortest
if (typeof gc === 'function') setTimeout(gc, 1000);
// longer in order to see indicators of gc being performed
if (typeof gc === 'function') {
setTimeout(function doGC() { gc(); process.stdout.write(' gc ') }, 1000);
}
Then run your app with the appropriate flags to expose the gc and force compaction.
node --always-compact --expose-gc app.js
Now you can wait for the garbage collection to occur and take a heapdump right after.
Alternatively you can add a hook to your app, i.e. a route, that will trigger manual gc
and invoke that before taking
a heapdump.
The usefulness of the information presented in the below views depends on how you authored your code. Here are a few rules to make your code more debuggable.
This requires little extra effort but makes is so much easier to track down which function is closing over an object and thus prevents it from being collected. Unfortunately CoffeeScript generates JS that has unnamed functions due to a bug in older Internet Explorers.
The below does not show as foo
in the snapshot:
var foo = function () {
[..]
}
This one will:
var foo = function foo() {
[..]
}
This one as well:
function foo() {
[..]
}
Properties and values are colored according to their types.
- a:property regular propertye, i.e.
foo.bar
- 0:element numeric index property, i.e.
arr[0]
- a:context var variable in function context, accessible by name from inside function closure
- a:system prop added by JS VM and not accessible from JS code, i.e. v8 internal objects
- yellow objects are referenced by JS
- red objects are detached nodes which are referenced by yellow background object
- shows top level entries, a row per constructor
- columns for distance of the object to the GC root, number of object instances, shallow size and retained size.
@
character is objects’ unique ID, allowing you to compare heap snapshots on per-object basis
- to the right of the View selector you can limit the objects by class name i.e. the name of the constructor function
- to the right of the class filter you can choose which objects to include in your summary (defaults to all)
- select objects allocated between heapdump 1 and heapdump 2 to identify objects that are still around in heapdump 3 but shouldn't be
- another way to archieve similar results is by comparing two heapdumps (see below)
- compares multiple snapshots to each other
- shows diff of both and delta in ref counts and freed and newly allocated memory
- used to find leaked objects
- after starting and completing (or canceling) the action, no garbage related to that action should be left
- note that garbage is collected each time a snapshot is taken, therefore remaining items are still referenced
- Take bottom line snapshot
- Perform operation that might cause a leak
- Perform reverse operation and/or ensure that action
2
is complete and therefore all objects needed to perform it should no longer be needed - Take second snapshot
- Compare both snapshots
- select a Snapshot, then Comparison on the left and another Snapshot to compare it to on the right
- the Size Delta will tell you how much memory couldn't be collected
Use at least three snapshots and compare those.
- Take bottom line snapshot Checkpoint 1
- Perform operation that might cause a leak
- Take snapshot Checkpoint 2
- Perform same operation as in 2.
- Take snapshot Checkpoint 3
- all memory needed to perform action the first time should have been collected by now
- any objects allocated between Checkpoint 1 and Checkpoint 2 should be no longer present in Checkpoint 3
- select Snapshot 3 and from the dropdown on the right select Objects allocated between Snapshot 1 and 2
- ideally you see no Objects that are created by your application (ignore memory that is unrelated to your action, i.e. (compiled code))
- if you see any Objects that shouldn't be there but are in doubt create a 4th snapshot and select Objects allocated between Snapshot 1 and 2 as shown in the picture below
- not supported by Node.js ATM
- now preferred over snapshot comparisons especially to track down memory leaks
- blue bars show memory allocations
- grey bars show memory deallocations
- only available when using Object Allocation Tracker
- needs to be enabled in settings General/Profiler/Record heap allocation stack traces
- shows stack traces of executed code that led to the object being allocated
- birds eye view of apps object structure
- low level, allows peeking inside function closures and look at VM internal objects
- used to determine what keeps objects from being collected
- GC roots actual GC roots used by garbage collector
- DOMWindow objects (not present when profiling Node.js apps)
- Native objects (not present when profiling Node.js apps)
Additional entry points only present when profiling a Node.js app:
- 1:: global object
- 2:: global object
- [4] Buffer reference to Node.js Buffers
- only available once Settings/General/Profiler/Show advanced heap snapshot properties is checked and browser refreshed afterwards
- shows dominators tree of heap
- similar to containment view but lacks property names since dominator may not have direct reference to all objects it dominates
- useful to identify memory accumulation points
- also used to ensure that objects are well contained instead of hanging around due to GC not working properly
- always shown at bottom of the UI
- displays retaining tree of currently selected object
- retaining tree has references going outward, i.e. inner item references outer item
- (global property) intermediate object between global object and an object refereced by it
- (roots) root entries in retaining view are entities that reference the selected object
- (closure) count of references to a group of objects through function closures
- (array, string, number, regexp) list of object types with properties which reference an Array, String, Number or regular expression
- (compiled code) SharedFunctionInfos have no context and standibetween functions that do have context
- (system) references to builtin functions mainly
Map
(TODO: confirm and more details)
- source of unintentional memory retention
- v8 will not clean up any memory of a closure untiil all members of the closure have gone out of scope
- therefore they should be used sparingly to avoid unnecessary semantic garbage
Keep in mind that most of these are someehwat out of date albeit still useful.
- chrome-docs memory profiling
- related demos including more resources
- chrome-docs Memory Analysis 101 overlaps with chrome-docs memory profiling
- chrome-docs heap profiling overlaps with chrome-docs memory profiling
- Chasing Leaks With The Chrome DevTools Heap Profiler Views
- heap profiler in chrome dev tools
- performance-optimisation-with-timeline-profiles time line data cannot be pulled out of a Node.js app currently, therfore skipping this for now
- timeline and heap profiler
- chromium blog
- Easing JavaScript Memory Profiling In Chrome DevTools
- Effectively Managing Memory at Gmail scale
- javascript memory management masterclass
- fixing memory leaks in drupal's editor
- writing fast memory efficient javascript
- imgur avoiding a memory leak situation in JS