User Interface Memory Managment

Revision as of 16:18, 30 October 2007 by Paulb (Talk | contribs) (Detecting Memory Leaks)


To be a good tool citizen inside EiffelStudio tools must properly handle resource manager above that provided by the Eiffel garbage collector. When working with any UI aspects in EiffelStudio objects should be "recyclable".

Recycling

Many UI classes inside EiffelStudio inherit a class EB_RECYCLABLE. It's purpose is to clean up resources and code links to other objects that may causes a memory leak.

Detecting Memory Leaks

EiffelStudio has an in-built debug tool call the Memory Tool. It can be used to provide statistics on the current number of objects alive in EiffelStudio as well and show the difference between two queried sessions.

The tool is to be used on the debugged version of EiffelStudio as it is a debug tool and not a debugging tool. To be a little cleared the tool shows the live view on the running process and not associated with the debugger.

Showing the Memory Tool

There are two ways to access the Memory Tool:

  • Press CTRL+ALT+D to show the "debug" menu, which is shown as the EiffelStudio build number at the end of the main menu strip. From there you can select Show Memory Tool
  • If you have a project loaded hold CTRL and left mouse click the Project Settings tool bar button.

Catching Leaks

In order to catch memory leaks you need to play spot the difference. Thankfully the tool does this for you between two snapshots of the live object map.

Here is the process of beginning to detect a memory leak. It will display the delta of objects added and not removed between two snapshots:

  • Once EiffelStudio is shown, display the Memory Tool.
  • Click the Refresh button to display an initial view of the live object map running in that version of EiffelStudio.

A filter has been applied here (more or this later), but this is what the Memory Tool should look something like:

Memory tool first run.png

The object count and delta will always match because it is the first snapshot taken.

  • Now open a new window either using the File | New Window menu item or pressing CTRL+N.
  • Once opened show your tool or perform any interaction that instantiates classes you have integrated into EiffelStudio.
  • Now close the new window and return back to the initial window with the Memory Tool.
  • Click Refresh on the tool again. This will recalculate the live object map and display a delta result showing the number of new objects in memory.

Here there is a leak. The delta is 1, where as it should be 0. This means that opening and closing a new window has leaked an instance of EB_DEVELOPMENT_WINDOW_AGENTS.

Memory tool leak.png

A memory leak occurs when your tool or any of it's associated objects retains a reference to an internal part of EiffelStudio, indicated by a delta of 1 or more. When this happens there can actually be a lot of noise in the view. To reduce noise and home in on the problem area do the following:

  • Toggle the Delta Only button to on so only those results with positive deltas are shown.
  • Enter a regular expression in the Type filter. For example, to show all EiffelStudio UI classes you would use: ^ES_|^EB_

Locating Memory Leaks

After you have found a memory leak, it is time to drill down and find out where the leak is occurring. The Memory Tool has implicit knowledge of EB_RECYCLABLE and displays an object's recycled state. In the example image shown in the previous section EB_DEVELOPMENT_WINDOW_AGENT has two live instances in the object map. The first has not been recycled as it is in use by the first opened window. The second instance however has been recycled, and even so still leaves two references preventing the garbage collector from reclaiming the object.

The problem lies in either or both of the
TUPLE [EB_DEVELOPMENT_WINDOW_AGENTS]<code> referrer instances. Expanding the referrer objects reveals their referrer objects and so on.
 
[[Image:Memory_tool_digging_deeper.png]]
 
This expanded view of the referrers indicate there is a single leak and not two. The first instance of <code>TUPLE [EB_DEVELOPMENT_WINDOW_AGENTS]
is referenced by the instance itself and the garbage collector is able to reclaim this object. The second instance however is reference from EB_CUSTOMIZED_TOOL_MANAGER. The leak is due to an agent on EB_DEVELOPMENT_WINDOW_AGENTS being extended on an action sequence in EB_CUSTOMIZED_TOOL_MANAGER.

This could be a nightmare to find but with the help of the debugger and a well placed breakpoint the agent routine can be located.

Locating an Agent

Information.png Note: In order to locate an agent leak you must be debugging EiffelStudio from a finalized version of EiffelStudio, performing the leak analysis on the debugged version of EiffelStudio.

  • In the debugger add a breakpoint on the first line of ES_MEMORY_TOOL_PANEL.on_row_expanded.
  • Now in the debugged version of EiffelStudio collapse the row (if it's not already) displaying the object of a PROCEDURE, FUNCTION or PREDICATE type and then expanded it again.

The debugger will not be broken into at the place breakpoint.

  • In a debugger Watch Tool add the expression a_row.data.
  • Expand the expression result and the debugger shows the name of the agent, which you can navigate to using pick and drop or the context menu.
  • Examine the callers of the agent and locate the area where it's added to an action sequence, or set on an object, and be sure to prune it from the. sequence or unset it in the object's EB_RECYCLABLE.internal_recycle