views:

471

answers:

4

I have a WPF App which is grinding to a halt after running out of memory...
It is basically a TreeView displaying nodes, which are instances of Linq To Sql OR Generated class ICTemplates.Segment. There around 20 tables indirectly linked via associations to this class in the OR designer.

<TreeView Grid.Column="0" x:Name="tvwSegments" 
                      ItemsSource="{Binding}" 
                      SelectedItemChanged="OnNewSegmentSelected"/>
<HierarchicalDataTemplate DataType="{x:Type local:Segment}" ItemsSource="{Binding Path=Children}"> 
...

// code behind, set the data context based on user-input (Site, Id)
KeeperOfControls.DataContext = from segment in tblSegments
   where segment.site == iTemplateSite && segment.id == iTemplateSid
   select segment;

I've added an explicit property called Children to the segment class which looks up another table with parent-child records.

public IEnumerable<Segment> Children
{
  get
  {
    System1ConfigDataContext dc = new System1ConfigDataContext();
    return from link in this.ChildLinks
      join segment in dc.Segments on new { Site = link.ChildSite, ID = link.ChildSID } equals new { Site = segment.site, ID = segment.id }
      select segment;
  }
}

The rest of it is data binding coupled with data templates to display each Segment as a set of UI Controls.

I'm pretty certain that the children are being loaded on-demand (when I expand the parent) going by the response time. When I expand a node with around 70 children, it takes a while before the children are loaded (Task manager shows Mem Usage as 1000000K!). If I expand the next node with around 50 children, BOOM! OutOfMemoryException

I ran the VS Profiler to dig deeper and here are the results

Summary Page Object Lifetimes Allocation

The top 3 are Action, DeferredSourceFactory.DeferredSource and EntitySet (all .Net/LINQ classes). The only user-classes are Segment[] and Segment come in at #9 an #10.

I can't think of a lead to pursue.. What could be the reason ?

A: 

Have you tried using a global DataContext instead of one for each element?

Creating all of the DataContext's each with there own query and results could be the cause of your memory bloat.

Noah
Updated question... I'm setting DataContext just once per query... not for each element/node.
Gishu
A: 

I don't know the exact solution but the new statement in join may cause this. Because for each relation a new object could be created(But as I mentioned, I don't know if it is correct).

Could you try this;

public IEnumerable<Segment> Children
{
  get
  {
    System1ConfigDataContext dc = new System1ConfigDataContext();
    return from link in this.ChildLinks
      join segment in dc.Segments on link.ChildSite == segment.site && link.ChildSID == segment.id
      select segment;
  }
}
yapiskan
the above snippet won't compile - error CS0744: Expected contextual keyword 'equals'. I've already had my skirmish with the join syntax in LINQ. The new is reqd - See http://stackoverflow.com/questions/373865/whats-the-best-way-to-model-parent-child-relationships-stored-in-a-join-table-in
Gishu
Hmm, I got the point. Thanks, by the way.
yapiskan
+1  A: 

maybe a using surrounding that DataContext ?

using(System1ConfigDataContext dc = new System1ConfigDataContext()){
  .... ?
}

also, have you tried using an sql profiler? might shed some light on the matter.

sirrocco
thanks Sirocco. You set me off on the right path... thanks! See my post below for details..
Gishu
A: 
Gishu
ChildLinks is probably LazyLoaded - that's why you get ObjectDisposedException :) . The best thing would probably be to have a datacontext for business transaction implementation. Similar to a DataContext per Session on the web.
sirrocco
So if I try to force execution to defeat deferred execution (take the results out into a List before returning), I shouldn't see this exception?
Gishu
Yes, or you could (working with the DataContext in place - in the Children property) set the DataLoadOptions on the context to load the ChildLinks when you load a segment. That would trigger an extra join and double the results - I'm not sure if L2S knows how to handle that.
sirrocco
And when I say double - I mean multiply :).
sirrocco