Tôi có ứng dụng có chế độ xem Chi tiết chính. Khi bạn chọn một mục từ danh sách 'chính', nó sẽ điền khu vực 'chi tiết' với một số hình ảnh (được tạo thông qua RenderTargetBitmap).RenderTargetBitmap GDI xử lý rò rỉ trong chế độ xem Chi tiết chính
Mỗi khi tôi chọn một mục chính khác từ danh sách, số lượng xử lý GDI được sử dụng bởi ứng dụng của tôi (như được báo cáo trong Process Explorer) tăng lên - và cuối cùng rơi xuống (hoặc đôi khi khóa) tại 10.000 GDI đang sử dụng.
Tôi đang thua lỗ về cách khắc phục điều này, vì vậy mọi đề xuất về những gì tôi đang làm sai (hoặc chỉ đề xuất cách nhận thêm thông tin) sẽ được đánh giá cao.
tôi đã đơn giản hóa ứng dụng của tôi xuống đến sau trong một ứng dụng mới WPF (.NET 4.0) được gọi là "DoesThisLeak":
Trong 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;
}
}
Trong 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>
Bạn có thể tạo lại sự cố nếu bạn nhấp vào mục đầu tiên trong danh sách, sau đó nhấn và giữ phím Con trỏ.
Từ khi nhìn vào! Gcroot trong WinDbg với SOS, tôi không thể tìm thấy bất cứ điều gì giữ cho các đối tượng RenderTargetBitmap còn sống, nhưng nếu tôi làm !dumpheap -type System.Windows.Media.Imaging.RenderTargetBitmap
nó vẫn hiển thị một vài nghìn trong số chúng chưa được thu thập.
Lưu ý, tôi cũng đã cố gắng lưu vào bộ nhớ cache ObservableCollection. Thật không may, việc giữ bộ sưu tập dường như cuối cùng cũng giữ được các xử lý GDI. –
Cảm ơn, điều đó thật tuyệt. Nó sửa chữa nó cho các ứng dụng mẫu, tôi chỉ cần cố gắng phù hợp mà vào các ứng dụng thực tế bây giờ. Tôi không chắc chắn lý do tại sao ObservableCollection giúp ở đây mặc dù. Nếu chỉ vì kích thước, thì Danh sách sẽ có cùng tác dụng. –
Wilka