16

システム: Windows XP SP3、.NET 3.5、4GB RAM、デュアル 1.6GHz

非常に大きな PNG を (ストーリーボード アニメーションを使用して) 読み込んで遷移させる WPF アプリケーションがあります。これらの PNG の解像度は 8190x1080 です。アプリケーションが実行されると、画像がキャッシュされているように見え、システム メモリが徐々に増えていきます。最終的にはシステムを停止させ、OutOfMemoryException をスローします。

これを解決するために私が現在取っている手順は次のとおりです。

1) アプリから BitmapSource オブジェクトを削除しています

2) BitmapSource をロードするときに、BitmapSource BitmapCacheOption を None に設定しています。

3) BitmapSource がロードされたら、それをフリーズしています。

4) ソースを使用するイメージへのすべての参照と、ソース自体への参照をすべて削除します。

5) 上記の手順が完了した後、手動で GC.Collect() を呼び出します。

WPFがこれらの画像のメモリにハングアップする理由と、それらの読み込みに使用されたメモリが適切に回復されるようにするための解決策を見つけたいと思っています。

4

1 に答える 1

28

あなたは確かにこれに多くの仕事をしました。主な問題は、BitmapCacheOption.Noneが、基になるBitmapDecoderのキャッシュを妨げないことだと思います。

これには、GC.Collect()の実行、300の異なるURIからの300の小さな画像のロード、GC.Collect()の再呼び出しなど、いくつかのトリッキーな解決策がありますが、単純な解決策は簡単です。

Uriからロードする代わりに、Streamを作成し、それをBitmapFrameのコンストラクターに渡します。

var source = new BitmapImage();
using(Stream stream = ...)
{
  source.BeginInit();
  source.StreamSource = stream;
  source.CacheOption = BitmapCacheOption.OnLoad;    // not a mistake - see below
  source.EndInit();
}

これが機能する理由は、ストリームからロードするとキャッシュが完全に無効になるためです。トップレベルのソースがキャッシュされないだけでなく、内部デコーダーもキャッシュされません。

なぜBitmapCacheOption.OnLoad?直感に反しているように見えますが、このフラグには2つの効果があります。キャッシュが可能な場合はキャッシュを有効にし、EndInit()でロードを発生させます。私たちの場合、キャッシングは不可能なので、それがすべて行われると、ロードがすぐに発生します。

明らかに、このコードをUIスレッドから実行してから、BitmapSourceをフリーズして、移動できるようにします。

また、なぜBitmapCreateOptions.IgnoreImageCacheを使用しなかったのか不思議に思うかもしれません。URIが指定されていないとキャッシュが不可能であるという事実を除けば、IgnoreImageCacheは画像キャッシュを完全に無視しません。読み取りのためにそれを無視するだけです。したがって、IgnoreImageCacheが設定されている場合でも、ロードされた画像はキャッシュに挿入されたままになります。違いは、キャッシュ内の既存の画像が無視されることです。

于 2009-11-06T05:01:25.697 に答える