none
[SL4/5] Strange DataTemplate memory leak

    General discussion

  • We have a huge application that uses Navigation heavily. We've noticed that when view is abandoned it is never collected by GC. In order to test the case, we've added explicit calls to GC.Collect/WaitForPendingFinalizers in Frame.Navigated handler. We've tested the scenario where user jumps between two views many times. Memory usage kept growing each time by ~1-2MB. So starting with 60 MB footprint we've ended up at 120 pretty soon. We've analyzed situation with windbg and it resulted in following (commands are in bold):

    0:040> !DumpHeap -type TestApp.ProjectListViewModel

     Address       MT     Size
    11255378 047f72f8       80    
    11361ea4 047f72f8       80    
    113a62b0 047f72f8       80    
    115b274c 047f72f8       80    
    11688904 047f72f8       80    
    116b2528 047f72f8       80    
    11c277a8 047f72f8       80    
    1a31690c 047f72f8       80    
    ...

    0:040> !gcroot 11255378

    Scan Thread 17 OSTHread 9c8
    ...
    Scan Thread 36 OSTHread 2dd4
    DOMAIN(0539F770):HANDLE(Pinned):57212f8:Root:  11e9b1e0(System.Object[])->
      10eae04c(System.Collections.Generic.Dictionary`2[[System.IntPtr, mscorlib],[System.Object, mscorlib]])->
      12d7acf0(System.Collections.Generic.Dictionary`2+Entry[[System.IntPtr, mscorlib],[System.Object, mscorlib]][])->
      1124bf7c(System.Windows.DataTemplate)->
      1124663c(TestApp.ProjectListView)->
      11255378(TestApp.ProjectListViewModel)

    0:040> !do 1124bf7c

    Name:        System.Windows.DataTemplate
    MethodTable: 5aacf424
    EEClass:     5a740598
    Size:        48(0x30) bytes
    File:        c:\Program Files (x86)\Microsoft Silverlight\5.0.60401.0\System.Windows.dll
    Fields:
          MT    Field   Offset                 Type VT     Attr    Value Name
    5aac53ac  4000434        4 ...eObjectSafeHandle  0 instance 1124bfb8 m_nativePtr
    5aac5574  4000435        8 ... System.Windows]]  0 instance 00000000 _valueTable
    794784ac  4000436       24       System.Boolean  1 instance        0 _propagateInheritanceChanged
    5aac1da8  4000437        c ....DependencyObject  0 instance 00000000 _inheritanceParent
    5aac591c  4000438       10 ...reTypeEventHelper  0 instance 1124bfac _coreTypeEventHelper
    5aaa778c  4000439       14 ...angedEventHandler  0 instance 00000000 DPChanged
    79458a44  400043a       18  System.EventHandler  0 instance 00000000 _inheritaneContextChanged
    5aaa7bb8  400043c       1c ...bject, mscorlib]]  0 instance 00000000 _treeChildren
    5aaa30b4  400043d       20 ...rnal.IManagedPeer  0 instance 00000000 _treeParent
    7947fd34  400043b        c ...flection.Assembly  0   shared   static _executingAssembly
        >> Domain:Value  1013df90:NotInit  0539f770:NotInit  <<
    5aaa3078  400058c       28 ....IManagedPeerBase  0 instance 1124663c _eventRoot
    5aac56b4  400058b      15c ...ependencyProperty  0   shared   static TemplateProperty
        >> Domain:Value  1013df90:NotInit  0539f770:10f01098 <<
    5aac56b4  400058d      160 ...ependencyProperty  0   shared   static DataTypeProperty
        >> Domain:Value  1013df90:NotInit  0539f770:10f01080 <<

    Apparently, The only thing that references view (and therefore viewmodel) is DataTemplate, and that's what prevents view/viewmodel from being collected. The DataTemplate instance in charge looks like it was abandoned (no tree children or parent set) but it still references view via its _eventRoot.

    Then we went ahead and removed DataGridTemplateColumn typed columns from DataGrid that is part of ProjectListView and repeated windbg the same test. It showed single instance of ProjectListViewModel that actually has no references and apparently will be collected by GC next time.

    This behavior was tested on 4.0.60129.0 and 5.0.60401.0 versions of Silverlight runtime (built for Silverlight 4 in both cases). Does it mean that problem with memory leak from inline templates is still present? Are there any feasible workarounds available or a ETA for this to be fixed?..

    I will also try converting the solution to build for SL5 and will report back.

    Tuesday, April 19, 2011 8:04 AM

All replies

  • Hi,

    Could you provide a repro project so that we can test it?

    Thanks.

     

    Regards

     

    Thursday, April 21, 2011 8:41 AM
  • I am having the exact same problem.

    It does not seem to be the inline datatemplate issue (because I have removed the inlines).

    Ants

    Wednesday, April 18, 2012 11:25 AM
  • Ok so I went ahead and tried to replicate the problem in its simplest form. Here is what I found:

    If I define a celltemplate like so:

    <DataTemplate x:Name="SharedTemplate">
                    <Grid/>                
    </DataTemplate>

    Yes that is correct, a pointless template.

    Then I connect it to a GridView like so:

     <telerik:GridViewDataColumn x:Name="CheckBoxColumn" Header="Shared" HeaderCellStyle="{StaticResource GridViewHeaderCellStyle1}" HeaderTextAlignment="Center" 
                                                Width="2*" IsFilterable="True" DataMemberBinding="{Binding NodeDefinition.Shared}" EditTriggers="None"
                                                CellTemplate="{StaticResource SharedTemplate}">
     </telerik:GridViewDataColumn>

    Then the leak occurs like so:

    omg

    If you go back to the datatemplate and remove the <Grid/> the leak vanishes. This does not make any sense, other than the fact that Telerik is involved which is mose likely part of the problem. Those guys cannot produce proper anything.

    
    
    Thursday, April 19, 2012 9:10 AM
  • Ok so I found a hack that compensates.

    Basically you have to attach an eventhandler to the RadGridView's hosting control's Unloaded event containing this code:

     foreach (var column in FileChildrenGrid.Columns)                                
         column.CellTemplate = null;                                    
                                    
     var fake = new RadGridView();                                
     fake.Columns.AddRange(FileChildrenGrid.Columns.Cast<object>().ToList());

    The thinking goes like this. As soon as you apply a CellTemplate to the RadGridView's DataColumn (maybe other GridViews/ItemsControls too?) the underlying Silverlight framework causes that leaky Style object (see above diagram) to point to the Column.

    Getting rid of this leak requires 2 steps.

    1.)Clear out all CellTemplates in RadGridView's Columns so that step 2 will work:

    2.)We need to re-add those columns to a fake RadGridView without the CellTemplates which causes that leaky Style reference to go away somehow, allowing the original RadGridView to be collected.

    Thursday, April 19, 2012 10:54 AM