WPF内存使用

11

应用:

  • WPF应用程序由一个上方的文本框和一个下方的列表框组成
  • 用户在文本框中输入字符串以查找员工,搜索结果显示在列表框中
  • 列表框使用数据模板显示元素(显示员工姓名、部门、电话和缩略图.)

实现:

  • 在应用程序启动时,我查询数据库并检索所有员工及其相关信息,以在列表框中显示。这些数据一直保留在内存中。
  • 应用程序启动后,所有可搜索数据都在内存中,并且搜索几乎是瞬时的。所有搜索都在已经在内存中的数据上执行。
  • 使用数据模板在列表框中显示搜索结果。每个列表框项都显示缩略图、姓名、电话、部门等信息。

问题:

  • 在启动时,内存使用量约为200MB。
  • 当通过新搜索或简单地滚动列表框更改数据时,内存消耗会增加。
  • 当用户缓慢滚动列表框时,内存增长得更快。随着滚动的上下,内存很快达到1GB。

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

为什么会出现这种情况?我该怎么解决?请帮忙!

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


实际上,“istbox正在创建用于显示员工图像的对象,并且在listboxitem离开窗口后没有释放给垃圾收集器” - 这是一种内存泄漏。 - arconaut
2
这只是语义问题,不会有任何影响,但当你有一个对象并且该对象持有内存时,这不是内存泄漏。例如,如果对象已经消失但内存仍然被分配,那么就会出现泄漏。 - Gus Cavalcanti
哦,也许你是对的,但这个定义可能只适用于非托管代码。而我在.NET世界中看到过这样的例子被定义为内存泄漏。 - arconaut
5个回答

8

冒昧地说,您遇到了内存泄漏问题。为什么不试试像 ANTS这样的工具来跟踪它呢?他们有一个免费试用版,虽然我从未使用过,但它口碑不错。

*其他性能分析工具也可用。

如果您不想使用另一个工具,可以尝试像递增静态成员一样,在每次创建类时递增并在每次实例销毁时递减。这将帮助您跟踪未被正确销毁的实例。


我同意Noel的观点 - 如果没有代码或一些分析报告,那信息是不足够的。我以前使用过Scitech的工具,这个工具非常有效:http://memprofiler.com/。我认为他们有一个免费试用版本,并且他们的网站上还有一些视频展示如何使用它。(我不是他们的员工,也没有任何利益关系 - 我只是觉得这是一个好工具)。 - JMarsch
我也同意Noel的观点。使用ANTS分析器等性能分析工具,查看哪些对象在内存中一直存在。从那里开始追踪问题应该就可以找到了。 - Judah Gabriel Himango

3

谢谢abmv。虽然这并没有回答我的问题,但我会查看你提供的数据虚拟化链接。我投了你的答案。 - Gus Cavalcanti

1

看起来确实是内存泄漏的问题。可能是DataTemplate中的某些UI元素保留了对其他对象的引用,即使在销毁UI元素时这些对象也应该保持活动状态。

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

只是一些猜测...正如其他人已经说过的那样,您可能真的想使用性能和内存分析器来查看您的应用程序。


0

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

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

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

那篇博客描述了一种情况,即:

  1. 在应用的ResourceDictionary中定义了样式。
  2. 该样式使用包含媒体效果(如DropShadowEffect)的控件模板。
  3. 媒体效果应使用StaticResource引用。

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


谢谢Josh。我看过这篇文章,但我认为它没有解决我的问题,因为:a)我所有对资源的访问都是通过使用StaticResource;b)我不使用任何位图效果;c)样式是在应用程序的ResourceDictionary(App.xaml)中定义的。 - Gus Cavalcanti
啊,真糟糕。你知道这些对象在垃圾回收中被保留在哪个级别吗?它显然认为这些对象还有引用存在。可能可视画布区域比实际画布大小小,导致仍在屏幕外的对象仍在更新吗? - Josh E
嗨,Josh, 大小不是因素,因为所有对象仍然被保留。当我创建BitmapImage时,如果我使用myBitmap.CacheOption = BitmapCacheOption.OnLoad,那么所有图像都会被创建,最终占用1GB的内存。如果我不缓存,则启动应用程序时大约使用200MB,但随着不断滚动,内存增加到1GB。 - Gus Cavalcanti

0
有一件事对我帮助很大,那就是使用一个包装Stream类的类。这在这里详细解释了,通过使用这种方法,我确实节省了很多内存。WPF确实会为每个图片保留对底层byte[]和stream的引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接