多次显示图像后出现 WPF OutOfMemory 异常
WPF OutOfMemory Exception after displaying images a couple of times
我使用 wpf 并利用 wpf 集装箱船模型创建了一个投票系统。在系统中,使用了一系列显示候选图片的用户控件。最终用户完成投票后,系统会自动退出并等待下一位用户登录。连续投票几次后,图片开始随机丢失一张一张。我查了一下,是因为out of memory异常。随着我继续对其进行压力测试,越来越多的图片开始消失。我有预感是因为系统没有处理之前的windows和已经显示的用户控件和图片。我能做些什么来处理 window 或至少确保已显示的图片在 window 关闭后被处理?
您可以做一些事情。首先是使用内存分析器。我个人喜欢 RedGate ANTS Memory Profiler 它会告诉你你的对象是否正在清理,我相信他们有一个你可以使用的免费试用版。
另外,您的图像是如何显示的? window 是否从磁盘加载它们?如果图片数量较少,我建议将它们放在 ResourceDictionary 中,如下所示:
<BitmapImage UriSource="/MyApp.Client;component/Images/Pinned.png" x:Key="Pinned" PresentationOptions:Freeze="True" />
<BitmapImage UriSource="/MyApp.Client;component/Images//Unpinned.png" x:Key="Unpinned" PresentationOptions:Freeze="True" />
然后在你的XAML中你可以使用:
<Image Source="{StaticResource: Unpinned}"/>
这将确保您的图片只加载一次。所有需要它的东西都会引用它。
另请记住,如果您在 window 上订阅了任何活动,它可以防止您的 window 关闭。当 window 关闭时,您应该始终取消引用您的事件。例如:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += DoStuff();
}
private RoutedEventHandler DoStuff()
{
//some code here
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
Loaded -= DoStuff();
}
}
当心泛型方法。例如,如果您这样做:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += (o, e) =>
{
//Do stuff here
};
}
}
没有办法取消引用,因为该方法是通用的,所以没有什么可以在您的关闭中删除它。这是内存泄漏和阻止 windows 关闭的一个非常常见的问题。
另一个经常被忽视的常见问题是定时器 class。如果您启动计时器然后关闭 window 而没有停止计时器,计时器 class 将保存对您的 window 的引用以防止它被关闭。始终确保在 window 关闭时停止计时器。
我使用 wpf 并利用 wpf 集装箱船模型创建了一个投票系统。在系统中,使用了一系列显示候选图片的用户控件。最终用户完成投票后,系统会自动退出并等待下一位用户登录。连续投票几次后,图片开始随机丢失一张一张。我查了一下,是因为out of memory异常。随着我继续对其进行压力测试,越来越多的图片开始消失。我有预感是因为系统没有处理之前的windows和已经显示的用户控件和图片。我能做些什么来处理 window 或至少确保已显示的图片在 window 关闭后被处理?
您可以做一些事情。首先是使用内存分析器。我个人喜欢 RedGate ANTS Memory Profiler 它会告诉你你的对象是否正在清理,我相信他们有一个你可以使用的免费试用版。
另外,您的图像是如何显示的? window 是否从磁盘加载它们?如果图片数量较少,我建议将它们放在 ResourceDictionary 中,如下所示:
<BitmapImage UriSource="/MyApp.Client;component/Images/Pinned.png" x:Key="Pinned" PresentationOptions:Freeze="True" />
<BitmapImage UriSource="/MyApp.Client;component/Images//Unpinned.png" x:Key="Unpinned" PresentationOptions:Freeze="True" />
然后在你的XAML中你可以使用:
<Image Source="{StaticResource: Unpinned}"/>
这将确保您的图片只加载一次。所有需要它的东西都会引用它。
另请记住,如果您在 window 上订阅了任何活动,它可以防止您的 window 关闭。当 window 关闭时,您应该始终取消引用您的事件。例如:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += DoStuff();
}
private RoutedEventHandler DoStuff()
{
//some code here
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
Loaded -= DoStuff();
}
}
当心泛型方法。例如,如果您这样做:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += (o, e) =>
{
//Do stuff here
};
}
}
没有办法取消引用,因为该方法是通用的,所以没有什么可以在您的关闭中删除它。这是内存泄漏和阻止 windows 关闭的一个非常常见的问题。
另一个经常被忽视的常见问题是定时器 class。如果您启动计时器然后关闭 window 而没有停止计时器,计时器 class 将保存对您的 window 的引用以防止它被关闭。始终确保在 window 关闭时停止计时器。