7

BitmapImages を膨大な数 (25000 など) で作成するアプリケーション (WPF) があります。フレームワークはいくつかの内部ロジックを使用しているように見えるため、作成後に約 300 MB のメモリが消費されます (150 仮想および 150 物理)。これらの BitmapImages は Image オブジェクトに追加され、Canvas に追加されます。問題は、これらのイメージをすべて解放してもメモリが解放されないことです。どうすればメモリを解放できますか?

アプリケーションは単純です: Xaml

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Canvas x:Name="canvas" Grid.ColumnSpan="2"></Canvas>
        <Button Content="Add" Grid.Row="1" Click="Button_Click"/>
        <Button Content="Remove" Grid.Row="1" Grid.Column="1" Click="Remove_click"/>
    </Grid>

分離コード

        const int size = 25000;
        BitmapImage[] bimages = new BitmapImage[size];
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var paths = Directory.GetFiles(@"C:\Images", "*.jpg");
            for (int i = 0; i < size; i++)
            {
                bimages[i] = new BitmapImage(new Uri(paths[i % paths.Length]));
                var image = new Image();
                image.Source = bimages[i];
                canvas.Children.Add(image);
                Canvas.SetLeft(image, i*10);
                Canvas.SetTop(image, i * 10);
            }
        }

        private void Remove_click(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < size; i++)
            {
                bimages[i] = null;
            }
            canvas.Children.Clear();
            bimages = null;
            GC.Collect();
            GC.Collect();
            GC.Collect();
        }

これは、画像を追加した後の ResourceManager のスクリーンショットです。 ここに画像の説明を入力

4

5 に答える 5

6

BitmapImage オブジェクトをフリーズしないと解放されないというバグが Wpf にありました。https://www.jawahar.tech/home/finding-memory-leaks-in-wpf-based-applicationsは、問題を発見した元のページです。これは Wpf 3.5 sp1 で修正されているはずですが、状況によってはまだ見られていました。次のようにコードを変更してみて、それが問題かどうかを確認してください。

bimages[i] = new BitmapImage(new Uri(paths[i % paths.Length]));
bimages[i].Freeze();

プロファイラーで Wpf が BitmapImage のイベントをリッスンし、それによってイメージを維持している他のインスタンスを確認したため、BitmapImage オブジェクトを定期的にフリーズします。

Feeze() 呼び出しがコードの明らかな修正ではない場合は、RedGate Memory Profiler などのプロファイラーを使用することを強くお勧めします。これは依存関係ツリーをトレースし、Image オブジェクトを保持しているものを示します。メモリー。

于 2012-06-26T08:10:20.490 に答える
1

これはまだ配列です

BitmapImage[] bimages = new BitmapImage[size];

配列は連続した固定長のデータ構造であり、配列全体にメモリが割り当てられると、その一部を再利用することはできません。別のデータ構造( などLinkedList<T>)を使用するか、ケースに適した他のデータ構造を使用してみてください

于 2012-06-26T07:58:56.687 に答える
1

BitmapImage メモリの再利用に関する私の経験を話しているだけです。私は .Net Framework 4.5 を使用しています。
シンプルな WPF アプリケーションを作成し、大きな画像ファイルを読み込みます。次のコードを使用して、メモリから画像をクリアしようとしました:

private void ButtonImageRemove_Click(object sender, RoutedEventArgs e)
    {

        image1.Source = null;
        GC.Collect();
    }

しかし、うまくいきませんでした。他の解決策も試しましたが、答えが得られませんでした。数日間苦労した後、ボタンを 2 回押すと、GC がメモリを解放することがわかりました。次に、ボタンをクリックしてから数秒後に GC コレクターを呼び出すこのコードを単純に記述します。

private void ButtonImageRemove_Click(object sender, RoutedEventArgs e)
    {

        image1.Source = null;
        System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(delegate
        {
            System.Threading.Thread.Sleep(500);
            GC.Collect();
        }));
        thread.Start();

    }

このコードは、DotNetFr 4.5 でテストされたばかりです。おそらく、下位の .Net Framework の BitmapImage オブジェクトをフリーズする必要があります。 レイアウトが更新されない限り、このコードの
編集は機能しません。
つまり、親コントロールが削除された場合、GC はそれを再利用できません。

于 2013-09-28T09:20:31.630 に答える