为什么我的 WPF Treeview 绑定到 LinqToSql 类会占用大量内存?

发布于 2024-07-11 05:24:14 字数 1882 浏览 8 评论 0原文

我有一个 WPF 应用程序,它在内存不足后停止运行...
它基本上是一个显示节点的 TreeView,这些节点是 Linq To Sql 或生成的类 ICTemplates.Segment 的实例。 在 OR 设计器中,大约有 20 个表通过关联间接链接到此类。

<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;

我在段类中添加了一个名为 Children 的显式属性,该属性查找另一个包含父子记录的表。

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;
  }
}

其余部分是数据绑定与数据模板相结合,将每个段显示为一组 UI 控件。

我非常确定子级是根据响应时间按需加载的(当我展开父级时)。 当我展开一个包含大约 70 个子节点的节点时,需要一段时间才能加载子节点(任务管理器显示内存使用情况为 1000000K!)。 如果我用大约 50 个子节点扩展下一个节点,轰隆隆! OutOfMemoryException

我运行 VS Profiler 进行更深入的研究,结果如下

摘要页面 对象生命周期 分配

前 3 名是 Action、DeferredSourceFactory.DeferredSource 和 EntitySet(全部.Net/LINQ 类)。 唯一的用户类是 Segment[] 和 Segment,排在第 9 和第 10 名。

我想不出要追寻的线索。原因可能是什么?

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 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

×纯※雪 2024-07-18 05:24:14

也许是围绕 DataContext 的使用?

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

另外,您是否尝试过使用sql profiler? 可能会对此事有所启发。

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.

最初的梦 2024-07-18 05:24:14

您是否尝试过使用全局 DataContext 而不是每个元素使用一个全局 DataContext?

使用自己的查询和结果创建所有 DataContext 可能会导致内存膨胀。

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.

好多鱼好多余 2024-07-18 05:24:14

我不知道确切的解决方案,但 join 中的新语句可能会导致此问题。 因为对于每个关系都可以创建一个新对象(但正如我提到的,我不知道它是否正确)。

你能试试这个吗?

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;
  }
}

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;
  }
}
海风掠过北极光 2024-07-18 05:24:14

问题似乎是创建多个 S1DataContext 对象,如 Sirocco 所提到的。
我尝试使用 using 语句来强制 Dispose 并使其符合收集条件。 然而,它导致了一个我无法理解的 ObjectDisposeException 。

  1. 该控件来自设置 DockPanel KeeperOfAllControls 数据上下文的行。
  2. [外部代码](显示在调用堆栈中)
  3. Segment.Children.get(具有带 dc 的 using 块)
  4. 回到步骤 1 中的行... ObjectDisposeException Linq 查询使用从 S1DataContext 本地实例检索的 tblSegments

无论如何,所以我假设有一些东西阻止创建多个 DataContext处置。 所以我尝试了单例DataContext
它有效!

  • TreeView 控件的响应速度显着提高,我尝试的每个节点最多在 3-4 秒内加载。
  • 我在每次获取/搜索之前放入 GC.Collect (用于验证),现在内存使用量保持在 200,000-300,000K 之间。

OR 生成的 System.Data.Linq.DataContext 似乎不会消失,除非显式处置它(占用内存)。 尝试在我的情况下处理它,但没有成功..即使两个函数都有自己的 using 块(没有 DataContext 的共享实例)。 虽然我不喜欢 Singleton,但我正在为开发人员制作一个小型内部工具,因此现在不介意它。我在网上看到的 LinqToSql 示例都没有强制执行 Dispose 调用。

所以我想问题已经解决了。 感谢所有充当更多眼球的人,让这个 bug 变得浅薄。

The issue seems to be the creation of multiple S1DataContext objects as Sirocco referred to.
I tried the using statement to force a Dispose and make it eligible for collection. However it resulted in an ObjectDisposedException that I can't make sense of.

  1. The control goes from the line that sets the data context of the DockPanel KeeperOfAllControls.
  2. [External Code] (shown in call stack)
  3. Segment.Children.get (has a using block with dc)
  4. Back at the Line in Step 1... ObjectDisposedException the Linq query uses tblSegments which is retrieved from a local instance of S1DataContext

Anyways so i assume that there is something that prevents multiple DataContexts from being created and disposed. So I tried a Singleton DataContext.
And it works!

  • the TreeView control is significantly more responsive, every node I tried loads in 3-4 secs max.
  • I put in a GC.Collect (for verification) before every fetch/search and now the memory usage stays between 200,000-300,000K.

The OR generated System.Data.Linq.DataContext doesn't seem to go away unless it is disposed explicitly (eating memory). Trying to Dispose it in my case, didn't pan out.. even though both functions had their own using blocks (no shared instance of DataContext). Though I dislike Singletons, I'm making a small internal tool for devs and hence don't mind it as of now.. None of the LinqToSql samples I saw online.. had Dispose calls mandated.

So I guess the problem has been fixed. Thanks to all the people that acted as more eyeballs to make this bug shallow.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文