我一直在使用32位C#WPF應用程序,該應用程序在ListBox中顯示大量大圖像(在許多情況下爲1080p)。問題是,保留在我的C#對象的BitmapSource對象(我已經綁定到)增加了內存顯着,因爲我已經創建的複製/複製的BitmapSource的字節渲染之前。如果我保留BitmapSource對象以便重用它或在其他地方重新顯示它,則由於複製之前渲染,我最終會得到原始圖像字節的多個副本。更具體地說,在渲染之前調用CopyPixels(Int32Rect sourceRect, Array pixels, int stride, int offset)
。帶有堆棧跟蹤的內存/堆分析證實了在渲染前字節被複制的想法。防止C#WPF BitmapSource在渲染前被複制
唯一的「解決方法」我已經創建,其產生的BitmapSource 每次需要時間如下:
ImageData data = _backendImage.getData();
SWIGTYPE_p_unsigned_char rawData = _backendImage.getRawData();
IntPtr dataPointer = SWIGTYPE_p_unsigned_char.getCPtr(rawData).Handle;
GC.Collect(); // forces garbage collection on not-displayed images
return Utilities.GenerateBitmapSource((int)_backendImage.getWidth(), (int)_backendImage.getHeight(), _backendImage.getByteOrder(), dataPointer, data.Count);
的最後一行有我自己的函數來實際產生的BitmapSource對象,出於這樣的問題的範圍。
解決方法是對性能極差,因爲我做的不只是一個,但每前的數據的兩個副本(一個進入的BitmapSource,一個渲染)呈現到列表框。保留BitmapSource可以刪除所有重複的複製操作,但對內存使用情況非常重要。
這裏是我的列表框XAML:
<ListBox Name="SlideShowListBox" ItemsSource="{Binding SlideData.PreviewData}"
SelectedIndex="{Binding SelectedIndex}"
ScrollViewer.VerticalScrollBarVisibility="Visible"
SelectionMode="Extended"
VirtualizingStackPanel.VirtualizationMode="Recycling">
<ListBox.ItemTemplate>
<DataTemplate>
<VirtualizingStackPanel Orientation="Horizontal" Margin="0, 2.5, 0, 2.5">
<Label Content="{Binding data.ImageNumber}" VerticalAlignment="Top" Width="30" HorizontalContentAlignment="Right" Margin="0,-6.5,0,0"/>
<Grid>
<Image Source="{Binding data.ImageThumbnail}" RenderOptions.BitmapScalingMode="HighQuality" VerticalAlignment="Top" HorizontalAlignment="Left"
Name="ListImage"
MaxWidth="{Binding ElementName=ListBoxItemSizer,
Path=ActualWidth, Converter={ikriv:MathConverter}, ConverterParameter=(x - 20)}">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding data.IsHidden}" Value="True">
<Setter Property="Opacity" Value="0.5"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Grid>
</VirtualizingStackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
問:有沒有什麼辦法來防止WPF從複製字節之前渲染的時候,我已經很存儲在RAM中的所有字節,並在圖像上稱爲.Freeze()
?我想我的圖像字節的一個副本在RAM中:不多也不少。
可能相關:.NET Memory issues loading ~40 images, memory not reclaimed - 似乎無關,因爲我從原始字節構建BitmapSource對象,而不是(文字)流對象。
編輯:有趣的澄清 - 我在兩個不同的屏幕上顯示這些BitmapSource項目在2個不同的列表框項目。如果我把周圍的對象時,內存使用僅增加了第一呈現的BitmapSource的,而不是在隨後的呈現,無論哪個屏幕或ListBox的的BitmapSource出現。