3
votes

I have a question about the Spark DataGrid and how it works in terms of garbage collection. What I'm finding is that if I dynamically add and remove columns from the DataGrid at runtime, the GridColumns and ItemRenderers never get freed from memory.

For instance, if I have a list with 10 items and I create 10 columns, there will be 100 ItemRenderers and 10 GridColumns. If I remove all of the columns, they are still there.

If I add 5 columns back, it does not appear to instantiate more GridColumns or ItemRenderers - there are still 100 total renderers and 10 columns in memory.

This doesn't happen with the MX DataGrid. As the columns are removed the ItemRenderers and and DataGridColumns get freed from memory, when I look at the profiler afterwards, I see 0 ItemRenderers and 1 DataGridColumn.

Does anybody have any idea about what would be going on here? Or am I just missing something?

Here is the code that I used to test the Spark DataGrid:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
    <fx:Declarations>
        <s:ArrayList id="dp">
            <fx:Object label="label 1"/>
            <fx:Object label="label 2"/>
            <fx:Object label="label 3"/>
            <fx:Object label="label 4"/>
            <fx:Object label="label 5"/>
            <fx:Object label="label 6"/>
            <fx:Object label="label 7"/>
            <fx:Object label="label 8"/>
            <fx:Object label="label 9"/>
            <fx:Object label="label 10"/>
        </s:ArrayList>
        <s:ArrayList id="columns">
            <s:GridColumn dataField="label"/>
        </s:ArrayList>
    </fx:Declarations>
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
    <s:DataGrid dataProvider="{dp}" columns="{columns}" width="100%" height="100%"/>

    <s:HGroup>
        <s:Button label="Add Column" click="columns.addItem(new GridColumn('label'))"/>
        <s:Button label="Remove Column" click="if( columns.length > 0 ) columns.removeItemAt(0)"/>
    </s:HGroup>
</s:Application>
2
"if I have a list with 10 items 10 items and I create 10 columns, there will be 100 ItemRenderers"; this is only true if your DataGrid is displaying 10 rows. If you're DataGrid displays 5 rows; then you have 50 itemRenderers. [Note: I'm not sure if Spark DataGrid creates all columns at once like the MX DataGrid does; if it does not you may have even fewer renderers; based on the number of displayed columns)JeffryHouser
+1 for providing a complete, runnable sample.JeffryHouser

2 Answers

1
votes

I haven't had a chance to look over the Flex 4.5 DataGrid code yet, but I would imagine they're using object pooling for the item renderers.

The DataGrid is all about speed, and what takes the most amount of time is normally the item renderers (especially instantiation). To keep the DataGrid fast, they don't 'destroy' the item renderers right away. It will hold onto them for x amount of time; or for some object pooling algorithms, never release them. It's easier to just keep them in memory since they're not suppose to be huge in the first place and have a quicker dynamic DataGrid.

Actually, I did a quick google search and I was right:

All of these DataGrid IFactory skin parts are required to be IVisualElements. In many cases they're just GraphicElements like Rects or Lines, which can be renderered quite efficiently because the Flex runtime's "display object sharing" support uses a single DisplayObject to render all of them. Just like item renderers, these visual elements are internally pooled and recycled, to avoid the cost creating and adding them when the DataGrid is scrolled.

It seems that item renderers are not only pooled within each DataGrid, but for all DataGrids. Very good practice I have to say. And trust me, this is very beneficial for Flex performance on DataGrids.

0
votes

I beleive the answer to your question is the "useVirtualLayout" property.

Instead of creating an item renderer for each child, you can configure the container to use a virtual layout. With virtual layout, the container reuses item renderers so that > it only creates item renderers for the currently visible children of the container. As a child is moved off the screen, possible by scrolling the container, a new child being scrolled onto the screen can reuse its item renderer.

To configure a container to use virtual layout, set the useVirtualLayout property to true for the layout associated with the container. Only DataGroup or SkinnableDataContainer with layout set to VerticalLayout, HorizontalLayout, or TileLayout supports virtual layout. Layout subclasses that do not support virtualization must prevent changing this prope"

Source: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/spark/layouts/supportClasses/LayoutBase.html#useVirtualLayout

Edit: Just found out that DataGrids only support VirtualLayouts, as it uses the custom "GridLayout". So maybe this isn't the answer to your question.