30行WPF应用程序内存泄漏

3
我有一个简单的WPF应用程序,包括一个带有橙色矩形和连续动画的窗口,该动画更改应用于矩形的模糊半径。目前,该应用程序正在两台计算机上进行灌注测试,以诊断与WPF相关的内存泄漏问题,该问题在较大程序中存在。
在第一台计算机上,内存使用量保持稳定,平均值略微振荡,频率与动画持续时间相同。测试程序已经可靠地运行了一个多星期而没有泄漏内存。该计算机运行windows 7 32位操作系统。
在第二台计算机上,内存使用情况也显示出相同的周期性行为,然而,每90秒左右,内存使用情况会增加约100kb。只要应用程序在运行,这种额外的增加就永远不会被回收。我曾经运行过这个程序,直到整个系统内存都被这个应用程序消耗完!一个矩形上的动态光芒消耗了4GB的内存!该计算机运行windows 7嵌入式32位操作系统。
两个平台之间存在显著的硬件差异,但两个系统都运行其各自硬件的最新驱动程序。
相同的编译后的exe文件在两台计算机上运行,没有附加调试器。应用程序的XAML代码如下:
<Window
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 x:Class="WpfAnimation.MainWindow"
 x:Name="Window"
 Title="MainWindow"
 Width="640" Height="480">
 <Window.Resources>
  <Storyboard x:Key="Flash" AutoReverse="True" RepeatBehavior="Forever" FillBehavior="Stop">
   <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Effect).(BlurEffect.Radius)" Storyboard.TargetName="rectangle">
    <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
    <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="15">
     <EasingDoubleKeyFrame.EasingFunction>
      <ElasticEase EasingMode="EaseOut"/>
     </EasingDoubleKeyFrame.EasingFunction>
    </EasingDoubleKeyFrame>
   </DoubleAnimationUsingKeyFrames>
  </Storyboard>
 </Window.Resources>
 <Window.Triggers>
  <EventTrigger RoutedEvent="FrameworkElement.Loaded">
   <BeginStoryboard Storyboard="{StaticResource Flash}"/>
  </EventTrigger>
 </Window.Triggers>

 <Grid x:Name="LayoutRoot">
  <Rectangle x:Name="rectangle" Fill="#FFFFA400" Margin="113,93,125,101" Stroke="Red" RadiusX="10" RadiusY="10" StrokeThickness="5">
   <Rectangle.Effect>
    <BlurEffect KernelType="Box" Radius="0"/>
   </Rectangle.Effect>
  </Rectangle>
 </Grid>
</Window>

这段代码是基于 .net Framework 4.0 构建的。这个 XAML 没有 C# 代码。

有没有可能解释一下为什么一个这么简单的程序会出现内存泄漏的问题?


能否把XAML贴出来呢? :) - Daniel Jennings
1
我敢打赌问题出在显卡驱动程序上。 - Robert Rossney
1
罗伯特,看起来你说得对。昨晚我启用了软件渲染开始了一项测试。在12小时内,软件渲染应用程序的内存使用量增加了2MB。同时,启用3D的副本目前的内存使用量为130MB。它们都从45MB的内存使用量开始。英特尔图形驱动程序就这样了!第一台正常运行的计算机(如上所述)配备了ATI卡和他们最新的驱动程序。 - oddsprite
2个回答

2

启用软件渲染已经修复了泄漏问题。在每个Window_Loaded事件中,我现在使用以下代码启用软件渲染:

public static void EnableSoftwareRendering(Visual visual)
        {
            try
            {
                HwndSource source = PresentationSource.FromVisual(visual) as HwndSource;
                HwndTarget target = source.CompositionTarget;
                target.RenderMode = RenderMode.SoftwareOnly;
            }
            catch
            { }
        }

我很快会测试这个。你知道为什么这个修复了问题吗? - TheLegendaryCopyCoder
根据问题本身的评论,我认为这是与图形驱动程序有关的问题。切换到软件渲染可以避免内存泄漏倾向的驱动程序。 - John Cummings

1

这是一个事件处理程序泄漏问题。

你的StoryBoard处理程序订阅了FrameworkElement.Loaded事件并将一直保留到最后。

我尝试像这样删除BeginStoryBoard:

    <EventTrigger RoutedEvent="UserControl.Unloaded"  SourceName="CellControl">
        <RemoveStoryboard BeginStoryboardName="MouseEnterStoryBoard"/>
    </EventTrigger>

但是它不起作用。所以我到现在还不知道如何修复它。

以下是来自dotMemory的处理程序跟踪。

System.Windows.Media.Animation.BeginStoryboard._inheritanceContext ->
System.Windows.EventTrigger._routedEventHandler ->
System.Windows.RoutedEventHandler._target ->
System.Windows.EventTrigger+EventTriggerSourceListener

你是怎么修复这个问题的? - Aivan Monceller

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