마스터 - 세부 정보보기가있는 앱이 있습니다. '마스터'목록에서 항목을 선택하면 '세부 정보'영역에 RenderTargetBitmap을 통해 생성 된 일부 이미지가 채워집니다.RenderTargetBitmap 마스터 - 세부 정보보기의 GDI 핸들 누출
목록에서 다른 마스터 항목을 선택할 때마다 프로세스 탐색기에보고 된대로 내 응용 프로그램에서 사용하는 GDI 핸들 수가 늘어나 결국 10,000 개의 GDI 핸들에서 넘어지고 결국 가라 앉습니다. 사용.
나는이 문제를 해결하는 방법을 놓치고있어, 내가 잘못하고있는 것에 대한 제안 (또는 더 많은 정보를 얻는 방법에 대한 제안)은 크게 감사하겠습니다.
나는 "DoesThisLeak"라는 새로운 WPF 응용 프로그램 (.NET 4.0)에서 다음 아래로 내 응용 프로그램을 단순화했습니다 : MainWindow.xaml.cs를에서
MainWindow.xaml에서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;
}
}
<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>
목록에서 첫 번째 항목을 클릭 한 다음 아래쪽 커서 키를 누른 상태에서 문제를 재현 할 수 있습니다.
SOS를 사용하여 WinDbg에서 gcroot를 보는 것으로부터 RenderTargetBitmap 개체를 계속 유지할 수는 없지만, 내가 수행 한 경우 !dumpheap -type System.Windows.Media.Imaging.RenderTargetBitmap
에 아직 수집되지 않은 개체가 수천 가지로 표시됩니다. 여기에 설명 된 솔루션을 사용
ObservableCollection도 캐싱하려고했습니다. 불행하게도 컬렉션을 가지고 있으면 궁극적으로 GDI 핸들도 보유하게 될 것입니다. –
고맙습니다. 그것은 샘플 애플 리케이션을 위해 그것을 해결하지, 난 그냥 실제 애플 리케이션에 피팅을 시도해야합니다. ObservableCollection이 왜 여기서 도움이되는지 나는 잘 모르겠습니다. 크기 때문인 경우 목록에 동일한 효과가 있어야합니다. –
Wilka