我有一個具有Master-Details視圖的應用程序。當您從「主」列表中選擇一個項目時,它會使用一些圖像(通過RenderTargetBitmap創建)填充「詳細信息」區域。RenderTargetBitmap GDI處理Master-Details視圖中的泄漏
每次我從列表中選擇一個不同的主項目時,我的應用程序使用的GDI句柄的數量(如Process Explorer中報告的)會增加 - 並且最終在10,000個GDI句柄上下降(或有時鎖定)正在使用。
我不知道如何解決這個問題,所以對於我做錯的任何建議(或只是關於如何獲得更多信息的建議)將不勝感激。
我已經簡化我的應用程序到名爲 「DoesThisLeak」 的新WPF應用程序(.NET 4.0)以下內容:
在MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
ViewModel = new MasterViewModel();
InitializeComponent();
}
public MasterViewModel ViewModel { get; set; }
}
public class MasterViewModel : INotifyPropertyChanged
{
private MasterItem selectedMasterItem;
public IEnumerable<MasterItem> MasterItems
{
get
{
for (int i = 0; i < 100; i++)
{
yield return new MasterItem(i);
}
}
}
public MasterItem SelectedMasterItem
{
get { return selectedMasterItem; }
set
{
if (selectedMasterItem != value)
{
selectedMasterItem = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("SelectedMasterItem"));
}
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class MasterItem
{
private readonly int seed;
public MasterItem(int seed)
{
this.seed = seed;
}
public IEnumerable<ImageSource> Images
{
get
{
GC.Collect(); // Make sure it's not the lack of collections causing the problem
var random = new Random(seed);
for (int i = 0; i < 150; i++)
{
yield return MakeImage(random);
}
}
}
private ImageSource MakeImage(Random random)
{
const int size = 180;
var drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawRectangle(Brushes.Red, null, new Rect(random.NextDouble() * size, random.NextDouble() * size, random.NextDouble() * size, random.NextDouble() * size));
}
var bitmap = new RenderTargetBitmap(size, size, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(drawingVisual);
bitmap.Freeze();
return bitmap;
}
}
在MainWindow.xaml
<Window x:Class="DoesThisLeak.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="900" Width="1100"
x:Name="self">
<Grid DataContext="{Binding ElementName=self, Path=ViewModel}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="210"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0" ItemsSource="{Binding MasterItems}" SelectedItem="{Binding SelectedMasterItem}"/>
<ItemsControl Grid.Column="1" ItemsSource="{Binding Path=SelectedMasterItem.Images}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
如果您單擊列表中的第一個項目,然後按住Down光標鍵,則可以重現該問題。
從看着!在WinDbg中的gcroot與SOS,我找不到任何保持RenderTargetBitmap對象活着的任何東西,但如果我做了!dumpheap -type System.Windows.Media.Imaging.RenderTargetBitmap
,它仍然顯示尚未收集的數千個RenderTargetBitmap對象。
請注意,我也嘗試緩存ObservableCollection也。不幸的是,持有這個集合似乎最終也能保持GDI的處理。 – 2012-01-29 21:22:03
謝謝,這很好。它確實解決了示例應用程序的問題,我只需要嘗試將其融入真正的應用程序。我不確定爲什麼ObservableCollection幫助這裏。如果僅僅是因爲大小,那麼列表應該具有相同的效果。 –
Wilka
2012-01-30 10:26:17