Difference between revisions of "Digging memory leaks of EiffelStudio"

(Definition)
(Typical Back to Once Routes)
Line 48: Line 48:
 
====Once managers focusing on one window====
 
====Once managers focusing on one window====
 
Take EB_DEBUGGER_MANAGER as an example. `debugging_window: EB_DEVELOPMENT_WINDOW' refers to the window that debugging tools are raised or to be raised. When a window is closed, we need to check if this window is the `debugging_window' and refresh this field, otherwise, the closed window will be referred. And not only do memory leaks occur, but also would it cause crash when one trying to operate on the non-existing window.
 
Take EB_DEBUGGER_MANAGER as an example. `debugging_window: EB_DEVELOPMENT_WINDOW' refers to the window that debugging tools are raised or to be raised. When a window is closed, we need to check if this window is the `debugging_window' and refresh this field, otherwise, the closed window will be referred. And not only do memory leaks occur, but also would it cause crash when one trying to operate on the non-existing window.
 +
 +
====Instances of EB_PREFERENCED_TOOL_BAR_TOGGLE_BUTTON are not recycled====
 +
`synchronizer' need to `deregister_host' when the button is useless. Normally `deregister_host' removes agents from preferences.
 +
 +
====EB_EDITOR_TOKEN_GRID_SUPPORT====
 +
`desynchronize*' MUST be called at disposal when `synchronize*' was once called.

Revision as of 22:23, 11 April 2007

Overview

The article is to help identify memory leaks of EiffelStudio and present one way of, to the maximum extend, getting rid of them. For now, with the tool in hand, it is difficult to guarantee that EiffelStudio is memory leak free. Every incorrect programmed operation could cause a leak, but not any operation we can check. One of the basic checks is opening a new window and close it, ensuring there is no leak by this operation. We call this OC operation. Though we can only do the basic to ensure what we are able to, this help one learn at programming in Eiffel how memory leak occurs and how to prevent from happening.

What is memory leak

Definition

Memory leaks are objects that will never be used in the system and by any means are still be referred directly or indirectly by once objects.

The objective of fixing a leak is find and cut one or more useless links to those once objects so that all the cycles/routes referenced can be garbage collected.

One thing one should keep in mind is that memory leaks we are talking about are not due to the language or compiler defeats, but the programmer makes them by programming illogically and incorrectly.

Example

Leak example.PNG

As demonstrated in the diagram, simple object relations in the memory is presented. Now Window manager is referring two windows. If they are all valid windows, we say there is NO memory leak here. But had one, say window_1, been destroyed, the whole branch of window_1 were memory leak. The bad link from Window manager to Window_1 illogically remains and prevents garbage collecting.

Fixing leaks by OC operation

Identifying memory leak existence

  1. Start debugging Eiffel Studio project, open a small project within the debugged Eiffel Studio.
  2. Ctrl + Left click on Project setting toolbar button. You will see the GC Statistics window. Click "Men map", all objects in current system are listed with information of Object Type, Count and Delta. Object Type is just as the name implies. Count means the total number of that object type in current system. Delta means the variation of number between two "Men map" operations. Click Mem map again and again until you don't see Delta value any more. Note that clicking on the header of Delta sorts.
  3. Carefully switch to the debugger Eiffel Studio window and open a new window, Ctrl + N is recommended, in case any mouse moving causes unwanted object variation. Close the new window.
  4. Carefully switch back to the GC statistics window. Click on "Mem map" ONCE. Now you see under Delta the variations of all object. Ideally there should not be any delta value. If so you can hooray, otherwise, the real job of fixing memory leak just starts.

In EiffelStudio, Ctrl + Alt + D brings up a hidden menu, the first item Memory Analyzer(MA) in which there is a Object Grid has almost the same function. Only note that before doing this one should disable auto refreshing. MA will be used for finding Back to Once routes.

Identifying leaks in code

Choosing a start object

Normally a closed EB_DEVELOPMENT_WINDOW is still connected, which means that the object cycles (it could be any kind of routes) involving this window are somehow connected to one or more once objects. The reason we choose start from EB_DEVELOPMENT_WINDOW is that it is a core class representing an Eiffel Studio window and it relates almost all modules of interfaces such as menus, toolbars and various tools.

Identifying the closed EB_DEVELOPMENT_WINDOW

Expand the node of EB_DEVELOPMENT_WINDOW, you will see two nodes. You might guess there must be one that was already closed. Yes, we are going to find the closed one. EB_DEVELOPMENT_WINDOW is derived from EB_RECYCLABLE. This class is used to help us with the job. When the window is closed, {EB_DEVELOPMENT_WINDOW}.recycle is called. Within the implementation we call `recycle' on almost all commands/tools so that references from those commands/tools are disconnected. By doing this, it is easy for us to find the closed window. Expand each of EB_DEVELOPMENT_WINDOW nodes, one with fewer client objects is the closed window. Some other leak objects like tools/commands can be found in the same way.

Typical Back to Once Routes

Now we can utilize Back to Once approach to find leaks in EiffelStudio. There are several typical ways causing memory leak in EiffelStudio.

Preference related

Preferences are initialized and referred by once object (CELL). As we use many of {PREFERENCE}.change_actions to reflect a changes of any type of preference. This could easily cause memory leaks. For example, when initializing a tool in a new opened window, we extend `agent {TOOL}.routine', into {PREFERENCE}.change_actions. This operation internally create a TUPLE [TOOL] referred by a PROCEDURE [TOOL, TUPLE] referred by a SPECIAL [PROCEDURE [ANY, TUPLE [ANY]]] of {PREFERENCE}.change_actions. When closing a window, if one do not remove this agent from {PREFERENCE}.change_actions, a leak occurs. Consequently, the object of a closed development window normally referred by the tool is not collected. Of course, other tools referred by this window will nor be collected.

Application related

An object of EV_APPLICATION is referred by once object. The same as previous case, there are incorrectly extending *actions without removing will cause memory leaks.

Menuable or toolbarable commands

Once objects of menuable or toolbarable commands can easily cause memory leaks. See EB_MENUABLE_COMMAND and EB_TOOLBARABLE_COMMAND, when we do new_*_item, we get a new item for the interface. But one should notice that in creation routine of those interface classes, i.e. EB_COMMAND_TOOL_BAR_BUTTON, EB_SD_COMMAND_TOOL_BAR_BUTTON and EB_COMMAND_MENU_ITEM, the item itself is inserted into the command object. This means that if one do not call `recycle' on interface items when they are not used anymore, leaks occurs in the once command objects.

Once managers focusing on one window

Take EB_DEBUGGER_MANAGER as an example. `debugging_window: EB_DEVELOPMENT_WINDOW' refers to the window that debugging tools are raised or to be raised. When a window is closed, we need to check if this window is the `debugging_window' and refresh this field, otherwise, the closed window will be referred. And not only do memory leaks occur, but also would it cause crash when one trying to operate on the non-existing window.

Instances of EB_PREFERENCED_TOOL_BAR_TOGGLE_BUTTON are not recycled

`synchronizer' need to `deregister_host' when the button is useless. Normally `deregister_host' removes agents from preferences.

EB_EDITOR_TOKEN_GRID_SUPPORT

`desynchronize*' MUST be called at disposal when `synchronize*' was once called.