qooxdoo

the new era of web development

 

Memory Management

Introduction

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.

Disposing an application

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.

Example destructor

destruct : function()
{
  this._data = this._moreData = null;
  this._disposeObjects("_buttonOk", "_buttonCancel");
  this._disposeArray("_children");
  this._disposeMap("_registry");
}
  • _disposeObjects: Supports multiple arguments. Dispose the objects (qooxdoo objects) under each key and finally delete the key from the instance.
  • _disposeArray: Disposes the array under the given key, but disposes all entries in this array first. It must contain instances of qx.core.Object only.
  • _disposeMap: Disposes the map under the given key, but disposes all entries in this map first. It must contain instances of qx.core.Object only.

How to test the destructor

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 variant qx.debug must be on. 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. You need to add a setting named "qx.disposerDebugLevel" with the value 1 to your config.json. See at the Support for finding potential memory leaks snippet how to change your configuration.

Log output from these settings chould 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

  • native Javascript types (Number, String, Object, ...) usualy don't need to be disposed.
  • for qooxdoo objects (e.g. qx.util.format.DateFormat, testgui.Report, ...) use _disposeObjects
  • for arrays or maps of qooxdoo objects use _disposeArray or _disposeMap.
  • be sure to cut all references to the DOM because garbage collection can not dispose object still connected to the DOM. This is also true for event listeners for example.

Table Of Contents

Previous topic

Debugging Applications

Next topic

Profiling Applications

This Page