jump to navigation

Memory Leak in Flex 3.2 Lists & Grids February 5, 2009

Posted by Hob in Adobe, Flex, memory leak, Open Source, RIA, User Experience, workday.
trackback

Ok…so to say that there’s a memory leak in Lists and Grids is a bit redundant as they all inherit from one class, ListBase, which is where the problem is, but a bit of redundancy can be eye-catching.

Anyway…recently I was tracking down an issue filed by one of our testers, and stumbled across a nasty little memory leak in the 3.2 SDK.  Adobe’s already corrected the problem in the 3.3 nightlies, but I thought I’d post my findings here on the chance that anyone else needs the fix in their 3.2 SDK.

The problem is a small class called StageEventProxy.  SystemManager creates an instance of StageEventProxy passing to it your listener whenever one of the following types of events is listened for from SystemManager:

  • MouseEvent.MOUSE_MOVE
  • MouseEvent.MOUSE_UP
  • MouseEvent.MOUSE_DOWN
  • Event.ACTIVATE
  • Event.DEACTIVATE

The problem is that StageEventProxy keeps a hard reference to your listener function.  This means that when garbage collection runs, that listener and the object its attached to will never get marked for garbage collection.

Now, you’re probably thinking, “I’ve never added any of those listeners to SystemManager so I’m free and clear.  Woot!”  Unfortunately you’re not off the hook just yet.  Adobe adds a MOUSE_UP listener to SystemManager in ListBase’s mouseDownHandler():

systemManager.getSandboxRoot().addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, true, 0, true);

The consequence of this line is that any object that’s an instance of a sub-class of this class (a quick search through the source code revealed List, DataGrid, AdvancedDataGrid, and TileList) will never be garbage collected once the user has clicked on any of the rows in the list. Additionally, because all UIComponents keep a hard reference to their parent component, the garbage collector will also neglect to clean up any of your list’s ancestors in the document hierarchy.

The implications of that for most people are that lists in pop-ups will cause the entirety of your pop-up to never get garbage collected. Here at Workday its a much larger issue, however. Our pages are dynamically created based on XML page definitions we get from the server. These pages are also dynamically unloaded when a new page is received. As a result of the patch for this fix, we’ve seen dramatically reduced memory usage over time in our Flex applications.

Here’s the culprit so you can see what was going on:

////////////////////////////////////////////////////////////////////////////////
//
//  ADOBE SYSTEMS INCORPORATED
//  Copyright 2003-2006 Adobe Systems Incorporated
//  All Rights Reserved.
//
//  NOTICE: Adobe permits you to use, modify, and distribute this file
//  in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////

package mx.managers.systemClasses
{

[ExcludeClass]

import flash.display.Stage;
import flash.events.Event;

/**
 * An object that filters stage
 */
public class StageEventProxy
{
	private var listener:Function;

	public function StageEventProxy(listener:Function)
	{
		this.listener = listener;
	}

	public function stageListener(event:Event):void
	{
		if (event.target is Stage)
			listener(event);
	}

}

}

Here’s the updated version Adobe’s including in the 3.3 SDK:

////////////////////////////////////////////////////////////////////////////////
//
//  ADOBE SYSTEMS INCORPORATED
//  Copyright 2003-2006 Adobe Systems Incorporated
//  All Rights Reserved.
//
//  NOTICE: Adobe permits you to use, modify, and distribute this file
//  in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////

package mx.managers.systemClasses
{

[ExcludeClass]

import flash.display.Stage;
import flash.events.Event;
import flash.utils.Dictionary;

/**
 * An object that filters stage
 */
public class StageEventProxy
{
	private var weakRef: Dictionary = new Dictionary(true);

	public function StageEventProxy(listener:Function)
	{
		this.weakRef[listener] = 1;
	}

	public function stageListener(event:Event):void
	{
		if (event.target is Stage)
		{
			for (var p:* in weakRef)
			{
				var f:Function = p as Function;
				f(event);
			}
		}
	}

}

}

And finally…Here’s a patch file you can drop in your Lib folder that will solve the problem: PATCH FILE

Comments»

1. Feng - February 6, 2009

it’s really good find. I am having a test with it.
flex builder point to SDK3.3 and recompile project, AdvancedDataGrid was not found. Just want a quick answer, sorry for this stupid question append here.

2. Hob - February 6, 2009

If I understand your problem, once you upgrade to the 3.3 SDK your compiler is saying it can no longer find the AdvancedDataGrid. That didn’t happen for me, but you can always force the Pro libraries back into Flex Builder by adding a source path to the data visualization source. You should find it at %FBPRO_Install_Folder%/sdks/3.2.0/fbpro/projects/datavisualization/src.

If you’re still having problems, try just using the patch file I posted. If you simply drop that into your lib folder, it will fix the problem in the 3.2 SDK.

3. Feng - February 6, 2009

thanks for your fast reply. your understanding is totally right. i have put patch file in the flex builder lib. do u mean i don’t have to change my flex code, it will work for me? because i have tested with it, but i did not see the expected change, so i upgrade it to sdk3.3 and met this issue.
i hurt my left ring finger when i want get more mango from its core, so please forgive me not type any uppercase letters here.

4. Hob - February 6, 2009

Dropping the patch in your lib folder should replace the 3.2 version of StageEventProxy with the version in the patch file (which is the 3.3 version). If you’re still seeing a memory leak it’s probably a prioritization problem. I had that problem at first, because I had added the Flex SDK source as a source path in my project, and anything that’s added as a source path gets a higher priority than things that are added as libs.

5. Feng - February 6, 2009

the patch name is SDK_18268_PATCH.swc, do u mean i should change its name and drop it in lib folder to replace other lib file?

6. Hob - February 6, 2009

No, the name doesn’t matter. Just make sure you don’t have the flex sdk source as a source path in your flex builder project. That will cause the changes in my patch file to be overridden by the default 3.2 code.

7. Feng - February 6, 2009

i got your point, now i will dig into it. thanks.

8. Alexey - March 24, 2009

2Feng
You should download Data Visualization for Flex 3.3 separately and unzip it to Flex 3.3. SDK folder
http://www.adobe.com/products/flex/flexdownloads/#flex_DataVisualization

9. Vijay Anand Mareddy - May 6, 2009

Hey all was well until i unintentionally did a mouse drag i think somewhere on the AdvDataGrid…

am getting an error at
[C:\Users\hob.spillane\Documents\Flex Builder 3\SDK_18268_PATCH\src\mx\managers\systemClasses\StageEventProxy.as:40]

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.controls.advancedDataGridClasses::AdvancedDataGridBase/http://www.adobe.com/2006/flex/mx/internal::columnItemRendererFactory()[C:\work\flex\dmv_automation\projects\datavisualisation\src\mx\controls\advancedDataGridClasses\AdvancedDataGridBase.as:1454]
at mx.controls::AdvancedDataGrid/http://www.adobe.com/2006/flex/mx/internal::columnItemRendererFactory()[C:\work\flex\dmv_automation\projects\datavisualisation\src\mx\controls\AdvancedDataGrid.as:2094]
at mx.controls.advancedDataGridClasses::AdvancedDataGridBase/http://www.adobe.com/2006/flex/mx/internal::columnItemRenderer()[C:\work\flex\dmv_automation\projects\datavisualisation\src\mx\controls\advancedDataGridClasses\AdvancedDataGridBase.as:1436]
at mx.controls::AdvancedDataGridBaseEx/columnDraggingMouseMoveHandler()[C:\work\flex\dmv_automation\projects\datavisualisation\src\mx\controls\AdvancedDataGridBaseEx.as:4916]
at mx.managers.systemClasses::StageEventProxy/stageListener()[C:\Users\hob.spillane\Documents\Flex Builder 3\SDK_18268_PATCH\src\mx\managers\systemClasses\StageEventProxy.as:40]

Hob - May 6, 2009

The error you’re seeing isn’t coming from StageEventProxy. StageEventProxy is simply calling the event listener which was registered. The error is actually being thrown from AdvancedDataGridBase. Unfortunately you’ll probably just have to spend some time in the debugger to see exactly why this is being thrown. It might be a configuration problem on the grid, but more than likely its simply a bug in the grid. We come across them all the time. Question is: Is this a critical error… Meaning, once you dismiss it, does your app completely stop responding, or do you continue to be able to use it. If the answer is the latter, then I wouldn’t worry too much about it. It’ll only ever be a problem for folks running the Flash debug player. If its the former, you’ve probably got at least a 1/2 day of debugging ahead of you.

10. diaper pee girl - July 20, 2009

emm. thank you ))


Leave a reply to Hob Cancel reply