>> I wrote a small class for finding the missing leaks. Actually it just
scans the qx-namespace and
>> prints all living object (and the first found reference-path to this
>> object).
Here it is for your usage (see below), simply called by:
----
var leakSearcher=new JSLeakSearcher();
leakSearcher.leakSearch();
---
>> Maybe I can incorporate your approach into this test or create an
>> additional one.
You can access statistics through the members 'referencedObjects' and
'referencedDisposedObjects'.
Each object-instance is just counted once, so this approach can be simply
incorporated into your testcases, with the same pattern you already use
(i.e. taking snapshots and then compare object-count).
------
/*
* This class traverses the whole Object-Graph in the qx-namespace,
finding any JSObject that won't be
* garbage collected due to other JS-references.
*
* Note that (currently) an instance of the class can only be used for ONE
call to the leakSearch function.
* Duplicate calls will result in undefined behaviour so just create a new
instance for every leak-search.
*
* Currently every found Object is counted and just printed to the debug
log in two categories:
* - normal qx-Objects which haven't been disposed yet (see member
'referencedObjects')
* - disposed objects, which still have references on them. (see member
'referencedDisposedObjects')
*
* The first category might be pointing to programming errors, if the
count constantly increases. Some object
* disposals might be missing.
* The second category is always pointing to programming errors - disposed
objects should never be referenced
* by any other objects any more.
*
* As a third category also all links into the Browser-DOM are printed. In
a normal application this shouldn't
* increase as well over time.
*
*
* Further ideas for this class: Just counting and writing to the log is
good enough for Unit-Testing where you
* make a 'before' and 'after' snapshot of a fixture that creates and
destroys some objects.
* Also finding leaks in the log is not too difficult, as leaking
references tend to accumulate at one spot which
* the eye can spot quite fast.
*
* This class could easily be extended to create a histogram of active
classes for debugging larger applications
* and spotting potential missing disposals.
*
*/
qx.Class.define("JSLeakSearcher",
{
extend : qx.core.Object,
members :
{
referencedObjects: 0,
referencedDisposedObjects: 0,
/* current call-stack */
__recursionInfo: new Array(),
/* Creates a string-representation of the recursion path. */
__recursionInfoToString : function() {
var recursionInfoString="";
for (var i=0;i<this.__recursionInfo.length; i++)
{
recursionInfoString+="->"+this.__recursionInfo[i];
}
return recursionInfoString;
},
/* starts a leak-search in the qx-namespace */
leakSearch : function() {
this.__leakSearch(window.qx, "qx");
},
/* internal leak-search-function. Will be called recursively */
__leakSearch : function(obj, currentPath)
{
// avoid traversing cycles, so don't follow any js-object, that is
alreadyMarked.
// Instead just increase reference-count
var marker='$$$leakSearcher_refCount_'+this.$$hash;
if (obj[marker])
{
obj[marker]++;
} else {
// mark object to avoid traversing in cycles
obj[marker]=1;
this.__recursionInfo.push(currentPath);
this.__updateStatistics(obj);
// Arrays are just traversed for each entry
if (obj instanceof Array)
{
this.__leakSearchArrayElements(obj);
}
// Objects are traversed for each of their keys
else if (obj instanceof Object)
{
this.__leakSearchObjectReferences(obj);
}
this.__recursionInfo.pop();
}
},
__updateStatistics: function(obj) {
// found a reference to a qooxdoo object ...
// Depending on the dispose-state issue a simple log or an error
log.
if (obj instanceof qx.core.Object)
{
if (obj.isDisposed())
{
this.error("Found disposed but still referenced Obj '" +
obj.classname + "' , hash '" + obj.$$hash+"', path: '"+this
__recursionInfoToString()+"'");
this.referencedDisposedObjects++;
} else {
this.info("Found living Obj '" + obj.classname + "' , hash '" +
obj.$$hash+"', path: '"+this.__recursionInfoToString()+"'");
this.referencedObjects++;
}
}
},
__leakSearchArrayElements: function(array) {
for (var i=0, l=array.length; i<l; i++)
{
var entry = array[i];
if (entry == null || !(typeof entry== "object"))
{
continue;
}
this.__leakSearch(entry, "["+i+"]");
}
},
__leakSearchObjectReferences: function(obj) {
// don't follow references into the DOM
if (qx.dom.Node.isElement(obj) || qx.dom.Node.isWindow(obj) ||
qx.dom.Node.isDocument(obj))
{
this.info("Stopped at link to DOM, path: '" + this
__recursionInfoToString() + "'");
} else {
for (var key in obj)
{
if (obj[key] == null || !obj.hasOwnProperty(key) || key==
'prototype')
{
continue;
}
this.__leakSearch(obj[key], key);
}
}
}
}
});
------
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
qooxdoo-devel mailing list
qooxdoo-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel