WPF 内存使用情况

Posted

技术标签:

【中文标题】WPF 内存使用情况【英文标题】:WPF Memory Usage 【发布时间】:2010-10-24 21:42:58 【问题描述】:

应用:

WPF 应用程序由顶部的文本框和下方的列表框组成 用户在TextBox中输入字符串查找员工,搜索结果显示在ListBox中 ListBox 使用 DataTemplates 显示元素(显示员工姓名、部门、​​电话和缩略图。)

实施:

在应用程序启动时,我查询数据库并检索要显示在 ListBox 中的所有员工和相关信息。这会一直保存在内存中。 应用程序启动后,所有可搜索的数据都在内存中,搜索几乎是即时的。所有搜索都在内存中的数据上执行。 搜索结果使用 DataTemplates 显示在 ListBox 中。缩略图、姓名、电话、部门等显示在每个 ListBox 项中。

问题:

启动时内存使用量约为 200MB。 随着列表框中的数据发生变化,无论是通过新搜索还是简单地向下滚动列表框,内存消耗都会增加。 当用户缓慢向下滚动列表框时,内存增加得更快。当您上下滚动时,内存会迅速达到 1GB。

没有代码手动创建控件 - 一切都是通过数据绑定完成的。

为什么我会看到这种行为?我能做些什么来修复它?请帮忙!

更新: 我发现问题不是内存泄漏。这里的问题是列表框正在创建对象以显示员工的图像,并且在列表框项离开窗口后没有为垃圾收集器释放。 CleanUpVirtualizedItem 事件如我所料发生,但内存仍未释放。有什么想法吗?

【问题讨论】:

嗯,实际上“istbox 正在创建对象以显示员工的图像,并且在 listboxitem 离开窗口后没有为垃圾收集器释放” - 是内存泄漏 这只是语义,没有任何区别,但是当你有一个对象并且该对象持有内存时,这不是内存泄漏。例如,泄漏是对象消失但内存仍然分配。 哦,也许你是对的,但这个定义可能只适合非托管代码。虽然我一直在 .NET 世界中看到这样的例子是内存泄漏的定义。 【参考方案1】:

冒着油嘴滑舌的风险,你有内存泄漏。为什么不尝试像ANTS* 这样的工具来追踪它。他们有免费试用版,我没用过,但口碑不错。

*其他分析工具可用。

如果您不想使用其他工具,可以尝试在每次创建类时增加静态成员并在每次释放实例时减少它。这将帮助您追踪未正确销毁的实例。

【讨论】:

我同意 Noel 的观点——没有一些代码或一些配置文件就没有足够的信息。我以前用过 Scitech 的工具,非常有效:memprofiler.com 我想他们有免费试用版,他们的网站上也有一些视频展示如何使用它。 (我不为他们工作或对他们有任何既得利益——我只是发现它是一个很好的工具)。 我也同意诺埃尔的观点。获取像 ANTS 分析器这样的分析器,看看有什么在记忆中还活着。你应该可以从那里找到它。【参考方案2】:

你可以使用

WPF Performance Suite

Optimizing WPF Application Performance

类似的问题困扰着我..(something like)

在应用程序启动时,我查询数据库并检索要显示在 ListBox 中的所有员工和相关信息。这会一直保存在内存中。

也许你可以修改你的代码来关注WPF: Data Virtualization

【讨论】:

感谢 abmv。虽然这不能回答我的问题,但我会查看您提供的数据虚拟化链接。我投票赞成你的答案。【参考方案3】:

这似乎真的是内存泄漏。很可能,DataTemplate 中的一些 UI 元素保留了对其他对象的引用,即使 UI 元素被销毁,这些对象也应该保持活动状态。

图像控件可能存在一些内存泄漏。尝试从模板中删除它并查看结果。另外,您是否订阅了控件的 Loaded 事件或类似事件中的任何事件?

不过只是一些猜测......正如人们在这里所说的那样,您可能真的想用性能和内存分析器来查看您的应用程序。

【讨论】:

【参考方案4】:

我注意到 WPF 和 .NET 3.5 SP1 在看似无害的情况下存在一些内存问题。

我确实找到了一些资源,但我不确定它们是否会对您有所帮助:

http://blog.ramondeklein.nl/?p=58

那篇博文描述了当

    样式在应用程序的 ResourceDictionary 中定义。 样式使用使用媒体效果的控件模板(即 DropShadowEffect)。 应使用 StaticResource 引用媒体效果

简而言之,我认为您的解决方案是确保任何媒体效果(投影等)都使用静态资源。

【讨论】:

谢谢乔希。我看过这篇文章,但我相信它不能解决我的问题,因为 a) 对我的资源的所有访问都是通过使用 StaticResource; b) 我不使用任何位图效果 c) 样式在应用程序的 ResourceDcitionary (App.xaml) 中定义。 啊,真可惜。你知道对象在 GC 中被持有的级别吗?它显然认为存在对对象的现有引用。是否有可能可视画布区域小于实际画布大小,导致“屏幕外”对象仍在更新? 嗨乔希,大小不是一个因素,因为所有的对象仍然被持有。当我创建 BitmapImage 时,如果我使用 myBitmap.CacheOption = BitmapCacheOption.OnLoad 则创建所有图像并且最终占用 1GB 内存。如果我不缓存,我会以大约 200MB 的大小启动应用程序,但随着我不断滚动,内存会增加到 1GB。【参考方案5】:

对我帮助很大的一件事是使用包装 Stream 类的类。这个在here有详细解释,果然用这个方法节省了很多内存。 WPF 确实保留了对每张图片的底层 byte[] 和流的引用。

【讨论】:

以上是关于WPF 内存使用情况的主要内容,如果未能解决你的问题,请参考以下文章

WPF 内存泄漏优化经历

WPF DataGrid.items.Refresh() 内存泄漏

WPF 使用frame加载page内存暴涨问题 坑

内存监测2

.NET 进程内存使用 = 5x CLR 堆内存?

记一次 .NET 某妇产医院 WPF内存溢出分析