Generally, qooxdoo's runtime will take care of most of the issues around object disposal, so you don't have to be too anxious if you get those 'missing destruct declaration' messages from a verbose disposer run.
To destruct existing objects at the end of your application is an important feature in the ever growing area of web applications. Widgets and models are normally handling a few storage fields on each instance. These fields need the dispose process to work without memory leaks.
Normally, JavaScript automatically cleans up. There is a built-in garbage collector in all engines. But these engines are more or less buggy. One problematic issue is that browsers differentiate between DOM and JavaScript and use different garbage collection systems for each (This does not affect all browsers, though). Problems arise when objects create links between the two systems. Another issue are circular references which could not be easily resolved, especially by engines which rely on a reference counter.
To help the buggy engines to collect the memory correctly it is helpful to dereference complex objects from each other, e.g. instances from maps, arrays and other instances. You don't need to delete primitive types like strings, booleans and numbers.
qooxdoo has solved this issue from the beginning using the included "dispose" methods which could be overridden and extended by each class. qooxdoo 0.7 introduced a new class declaration. This class declaration supports real "destructors" as known from other languages. These destructors are part of the class declaration. The new style makes it easier to write custom destructor/disposer methods because there are many new helper methods and the whole process has been streamlined to a great extend.
You can dispose any qooxdoo based application by simply calling qx.core.ObjectRegistry.shutdown(). The simplest possibility is to use the command line included in Firebug. Another possibility is to add a HTML link or a button to your application which executes this command.
You can look at the dispose behaviour of your app if you set the disposer into a verbose mode and then invoke it deliberately while your app is running. This will usually render your app unusable, but you will get all those messages hinting you at object properties that might need to be looked after. How-To instructions can be found here. But mind that the disposer output contains only hints, that still need human interpretation.
destruct : function()
{
this._data = this._moreData = null;
this._disposeObjects("_buttonOk", "_buttonCancel");
this._disposeArray("_children");
this._disposeMap("_registry");
}
The destructor code allows you an in-depth analysis of the destructors and finds fields which may leak etc. The DOM tree gets also queried for back-references to qooxdoo instances. These checks are not enabled by default because of the time they need on each unload of a typical qooxdoo based application.
To enable these checks you need to select a variant and configure a setting.
The environment setting qx.debug must be true. The setting qx.disposerDebugLevel must be at least at 1 to show not disposed qooxdoo objects if they need to be deleted. A setting of 2 will additionally show non qooxdoo objects. Higher values mean more output. Don't be alarmed if some qooxdoo internal showing up. Usually there is no need to delete all references. Garbage collection can do much for you here. For a general analysis 1 should be enough, a value of 2 should be used to be sure you did not miss anything. You can use the following code to adapt your config.json:
{
"jobs" :
{
// existing jobs ...
"source-disposerDebug" :
{
"desc" : "source version with 'qx.disposerDebugLevel' for destruct support",
"extend" : [ "source" ],
"environment" :
{
"qx.disposerDebugLevel" : "2"
}
}
}
}
This snippet is also available at the Support for finding potential memory leaks .
Log output from these settings could look something like this:
35443 DEBUG: testgui.Report[1004]: Disposing: [object testgui.Report]FireBug.js (line 75)
Missing destruct definition for '_scroller' in qx.ui.table.pane.FocusIndicator[1111]: [object qx.ui.table.pane.Scroller]Log.js (line 557)
Missing destruct definition for '_lastMouseDownCell' in qx.ui.table.pane.Scroller[1083]: [object Object]Log.js (line 557)
036394 DEBUG: testgui.Form[3306]: Disposing: [object testgui.Form]FireBug.js (line 75)
Missing destruct definition for '_dateFormat' in qx.ui.component.DateChooserButton[3579]: [object qx.util.format.DateFormat]Log.js (line 557)
Missing destruct definition for '_dateFormat' in qx.ui.component.DateChooserButton[3666]: [object qx.util.format.DateFormat]Log.js (line 557)
The nice thing here is that the log messages already indicate which dispose method to use: Every "Missing destruct..." line contains a hint to the type of member that is not being disposed properly, in the "[object ...]" part of the line. As a rule of thumb
qooxdoo contains a built-in dispose profiling feature that finds undisposed objects. This is useful mainly for applications that create and destroy objects as needed during their lifetime (instead of creating them once and re-using them). It cannot be used to find undisposed objects left over after the application was shut down.
Dispose profiling works by disabling a feature in qooxdoo's Object Registry where the hash codes used to identify objects are reused. That way, it is possible to iterate over all objects created between two specified points in the application's lifecycle and check if they're disposed. Since hash reusing is a performance feature, dispose profiling should only be activated for the development version of an application. It is activated by enabling the qx.debug.dispose environment setting for a compile job, e.g. source-script:
"source-script" :
{
"environment" :
{
"qx.debug.dispose" : true
}
}
After building the application, the dispose debugging workflow is as follows: