ListBoxに大量の大きな画像(多くの場合1080p)を表示する32ビットC#WPFアプリケーションで作業していました。問題は、私が作成したBitmapSourceのバイトがレンダリングの前に複製/コピーされるため、(私がバインドした)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オブジェクトを生成することがあり、最終的なラインは、とこの問題の範囲外です。
私はListBoxにレンダリングする前に、1つではなく2つのデータコピー(BitmapSourceに1つ、レンダリングに1つ)を実行するので、回避策はパフォーマンスが非常に悪いです。 BitmapSourceをそのままにしておくと、すべての複製操作が削除されますが、メモリ使用量は非常に重いです。ここで
は私のListBox 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>
質問:前に私はすでにRAMのすべてのバイトを格納していますし、画像上.Freeze()
を求めているときに、レンダリングバイトをコピーからWPFを防ぐために、どのような方法があります?画像のバイトのコピーをRAMに保存したいと思います。
おそらく関連:.NET Memory issues loading ~40 images, memory not reclaimed - (リテラル)ストリームオブジェクトではなく、生のバイトからBitmapSourceオブジェクトを構築しているため、無関係です。
編集:興味深い説明 - 2つの異なる画面上の2つの異なるListBoxアイテムにこれらのBitmapSourceアイテムを表示しています。オブジェクトを保持すると、BitmapSourceが表示される画面またはリストボックスに関係なく、RAM使用量がの最初のレンダリングで増加し、その後のレンダリングでは増加しません。