Difference between revisions of "User Interface Memory Managment"

m
m (Recycling)
Line 6: Line 6:
 
== Recycling ==
 
== 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.
 
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.
 +
 +
== Using EB_RECYCLABLE ==
 +
To use [[EB_RECYCLABLE]] one has to simply inherit it and implement the deferred routine <code>internal_recycle</code> where you should explicitly recycle and object on the Current class instance that are no longer required, prune agents added to action sequences and generally unset entities of auxiliary objects to prevent memory leaks.
 +
 +
It's not recommended to detach class attributes in <code>internal_recycle</code> unless necessary because of the auto-recycling capabilities of [[EB_RECYCLABLE]]. Instead redefine <code>internal_detach_entities</code> to perform explicit detachment.
 +
 +
{{Note|Much of the EiffelStudio code base includes detachment of entities in internal_recycle because the auto-recycle functionality was performed by [[ES_RECYCLER]] in the [[6.0]] release. [[ES_RECYCLER]] is deprecated and should not be use.}}
 +
 +
=== Automatic Recycling ===
 +
The whole process of explict recycling in <code>internal_recycle</code> is fraught with potential bug scenarios. Forgetting or being unaware that a created object is in fact a recyclable object can cause a leak. This is where automatic recycling comes in.
 +
 +
The automatic recycling capabilities of [[EB_RECYCLABLE]] does not care if an object is actually "recyclable" as it may not be statically but could be dynamically. In addition an object may have started out non-recyclable but was changed somewhere down the line to implement [[EB_RECYCLABLE]]. In that respect objects created in a class implementing [[EB_RECYCLABLE]] and should be cleaned up when the container object is recycled should use the automatic recycling facilities.
 +
 +
=== Automatic Recycle and Destroy ===
 +
[[EB_RECYCLABLE]] provides two routines for descending classes to use; <code>auto_recycle</code> and <code>delayed_auto_recycle</code>. <code>auto_recycle</code> simply accepts an object of type [[ANY]] and if that object implements [[EB_RECYCLABLE]], it will be recycled when the container object is. <code>delayed_auto_recycle</code> works a little different in that it takes an agent. The agent is used to "fetch" the recyclable object at recycle-time. This is useful when objects are dynamically or lazily created, there is uncertainly about the attached state of an entity of an object or if a object's attribute is constantly changing.
 +
 +
{{Note|Automatic recycling does not detach the object which was automatically recycled. If an object must detached to prevent memory leaks then a container object should define <code>internal_detach_entities</code>.}}
 +
 +
[[EB_RECYCLABLE]] recycling has another assisting function, it will automatically destroy [[EiffelVision2]] objects implementing [[EB_RECYCLABLE]]. <code>destroy</code> will only be called for the implementing [[EB_RECYCLABLE]] [[EiffelVision2]] object and not any of it's attributes, unless they are automatically recycled and implement [[EB_RECYCLABLE]] also.
 +
 +
=== Automatic Agent Removal ===
  
 
== Detecting Memory Leaks ==
 
== Detecting Memory Leaks ==

Revision as of 09:00, 31 October 2007

Construction.png Not Ready for Review: This Page is Under Development!

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.

Using EB_RECYCLABLE

To use EB_RECYCLABLE one has to simply inherit it and implement the deferred routine internal_recycle where you should explicitly recycle and object on the Current class instance that are no longer required, prune agents added to action sequences and generally unset entities of auxiliary objects to prevent memory leaks.

It's not recommended to detach class attributes in internal_recycle unless necessary because of the auto-recycling capabilities of EB_RECYCLABLE. Instead redefine internal_detach_entities to perform explicit detachment.

Information.png Note: Much of the EiffelStudio code base includes detachment of entities in internal_recycle because the auto-recycle functionality was performed by ES_RECYCLER in the 6.0 release. ES_RECYCLER is deprecated and should not be use.

Automatic Recycling

The whole process of explict recycling in internal_recycle is fraught with potential bug scenarios. Forgetting or being unaware that a created object is in fact a recyclable object can cause a leak. This is where automatic recycling comes in.

The automatic recycling capabilities of EB_RECYCLABLE does not care if an object is actually "recyclable" as it may not be statically but could be dynamically. In addition an object may have started out non-recyclable but was changed somewhere down the line to implement EB_RECYCLABLE. In that respect objects created in a class implementing EB_RECYCLABLE and should be cleaned up when the container object is recycled should use the automatic recycling facilities.

Automatic Recycle and Destroy

EB_RECYCLABLE provides two routines for descending classes to use; auto_recycle and delayed_auto_recycle. auto_recycle simply accepts an object of type ANY and if that object implements EB_RECYCLABLE, it will be recycled when the container object is. delayed_auto_recycle works a little different in that it takes an agent. The agent is used to "fetch" the recyclable object at recycle-time. This is useful when objects are dynamically or lazily created, there is uncertainly about the attached state of an entity of an object or if a object's attribute is constantly changing.

Information.png Note: Automatic recycling does not detach the object which was automatically recycled. If an object must detached to prevent memory leaks then a container object should define internal_detach_entities.

EB_RECYCLABLE recycling has another assisting function, it will automatically destroy EiffelVision2 objects implementing EB_RECYCLABLE. destroy will only be called for the implementing EB_RECYCLABLE EiffelVision2 object and not any of it's attributes, unless they are automatically recycled and implement EB_RECYCLABLE also.

Automatic Agent Removal

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] referrer instances. Expanding the referrer objects reveals their referrer objects and so on.

Memory tool digging deeper.png

This expanded view of the referrers indicate there is a single leak and not two. The first instance of 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