Tracking Memory Leaks
From Vexi
Contents |
Introduction
Vexi is garbage collected, however it is still possible to get memory leaks in garbage collected environments. The principal is always the same. Certain bits of memory exist for the lifetime of a program, sometimes these are called the static roots (In Vexi the static context of a template is never freed). If an object is indirectly linked to one of these static roots by a chain of references then it cannot be GC'd. Generally put if obj A is referenced after its no longer of any use by obj B that outlives A then A is a leak. It will leak for at least the lifespan of B.
Particular care needs to be taken when dealing with functions (which are closures in JavaScript) as they can see everything in their scope and create leaking references inadvertently. If a short lived template instantiation places traps on a longer lived object and does not remove them when it is finished with them, then this will be a memory leak. This scenario is the exact equivalent problem that one gets with listeners in Java Swing, the classic way to get a memory leak in visual environments.
Enough stalling, how are leaks tackled in Vexi?
Preparation
You will need to us the Vexi devl for executing your programs when looking for the leak. You may need to build this from subversion. It contains a facility based on the excellent INSANE library. This blog entry shows its how it is used in a plain old java environment.
Locating the leak
If the leak is a repeated one that will come to dominate the other objects allocated on the heap then pressing F12 will show the most frequently occurring object creations by their back traces at the time of their creation. For example running the Vexi demo and pressing F12 is shown below. There is no leak, but if there were then this information should tell us where it is allocated.
152 147 org.vexi.lib.text.word:14(apply) org.vexi.lib.text.block:295 org.vexi.lib.text.block:277 (trap on getword) org.vexi.lib.text.edit:1553 (trap on text) vexi.util.redirect:28 (trap on text) vexi.util.redirect:15 (trap on text) org.vexi.demo.about:47 (trap on text) org.vexi.demo.about:46(apply) org.vexi.demo.about:25(apply) org.vexi.demo.about:9(apply) org.vexi.demo.main:15(apply) org.vexi.demo.main:13(apply) org.vexi.demo.main:10(apply) main:4(apply) 75 org.vexi.lib.text.word:14(apply) org.vexi.lib.text.block:295 org.vexi.lib.text.block:277 (trap on getword) org.vexi.lib.text.edit:1553 (trap on text) vexi.util.redirect:28 (trap on text) vexi.util.redirect:15 (trap on text) org.vexi.demo.about:27 (trap on text) org.vexi.demo.about:26(apply) org.vexi.demo.about:25(apply) org.vexi.demo.about:9(apply) org.vexi.demo.main:15(apply) org.vexi.demo.main:13(apply) org.vexi.demo.main:10(apply) main:4(apply) ... 53 org.vexi.demo.demomenus:59 org.vexi.demo.demomenus:9(apply) org.vexi.demo.main:12(apply) org.vexi.demo.main:10(apply) main:4(apply)
Non repeated or rarely repeated leaks will be harder to find, but are correspondingly less severe.
Finding the reference chain
The initial reference is not usually the one that is causing the leak. So having the backtrace is not always enough to work out where an object is leaking.
You need to modify the code where you suspect the leak to be occuring to place a special marker object on the suspected leak. For example in the context of a template whose instantiations do not seem to get GC'd adding this line will place the marker.
thisbox.MARKER = vexi.devl.MARKER;
The first time this object is accessed it returns a special object. All subsequent times it will just return null. Now execute the program until you know that the marker has been placed and the memory leaked. Press F11 and wait for the processing of the heap to complete (this could take minutes). If the marker was placed on a leak then a chain of references will get displayed. This is a mixture of JS objects and java ones. The JS objects are not indented, and preceding them is the source:line position where they were allocated.
// TODO expand on the last section, show an example 'reference chain'
// TODO replace the Vexi Demo stack dump with a dump of a real example.

