質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.05%

WPFでキャンパスに画像を描画してビットマップ化するとメモリリークする

受付中

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 5,984

SKawaguchi

score 10

前提・実現したいこと

WPFでPNGファイルを読み込み、加工した後でPNGファイルに書き込むプログラムを作成しています。
メモリーリーク(1.2Gbyte)がどうしても取れないため、ご教授をお願いします。

発生している問題・エラーメッセージ

renderBitmap.Render(tempCanvas) 実行時に大量に消費するメモリを、GCで解放できない。

該当のソースコード

void func()
{
    FileStream rfs = new FileStream("test.png", FileMode.Open); //10000x10000のPNGファイル
    Image image = new Image() { Source = BitmapFrame.Create(rfs) };
    image.Source.Freeze();

    Canvas tempCanvas = new Canvas() {Width = 10000, Height = 10000 };
    Size size = new Size(10000, 10000);

    Canvas.SetLeft(image, 0);
    Canvas.SetTop(image, 0);
    Canvas.SetZIndex(image, 1);
    tempCanvas.Children.Add(image);

    tempCanvas.Measure(size);
    tempCanvas.Arrange(new Rect(size));

    RenderTargetBitmap renderBitmap = new RenderTargetBitmap( (int)size.Width, (int)size.Height, 96.0d, 96.0d, PixelFormats.Pbgra32 );
    renderBitmap.Render(tempCanvas);
    renderBitmap.Freeze();

    using (FileStream wfs = new FileStream("Test2.png", FileMode.Create))
    {
        BitmapEncoder encoder = new PngBitmapEncoder();
        try
        {
            encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
            encoder.Save(wfs);
        }
        catch 
        {
        }
    }

    image = null;
    tempCanvas = null;
    renderBitmap = null;

//    Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.SystemIdle);
//    Dispatcher.Run();
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
}

試したこと

Freeze()や、null等の参照を消す処理を入れてみたのですが効果はありませんでした。

補足情報(言語/FW/ツール等のバージョンなど)

WPF
.net freamework4
C#
Windows8.1
Visual Studio 2013 pro

※上記ソースコードはusingの追加とファイルを用意していただければ、コピペで動作します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

0

こんにちは。
ぱっと見ですが、rfsのDispose()を呼んでいないように見えます。
そちらの修正で解決しないでしょうか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/06 14:52

    rfs.Close();
    rfs.Dispose();
    を追加しましたがリークに変化はないようです。

    キャンセル

0

上記コード実行してみましたがそのような事象は起こりませんでした。
他に原因があると考えられます。

他にコードがあればそれを調査してみてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/06 15:45

    ありがとうございます。
    指摘された通り、他に原因がないか調べていたところ、リリースビルドとデバッグビルドで動作が変わることがわかりました。
    デバッグビルドだとメモリが解放されないようです...
    デバッガが使えないのは非常につらいですが頑張ってみます。

    キャンセル

  • 2016/09/07 09:08 編集

    リリースビルドでもまれにリークが発生するようです。
    ※デバッグビルドだと、今のところ100%再現します。

    上記関数は、WPFアプリケーションのスケルトンを作成後、Window_Loaded()イベントを追加してその中でfunc()を呼んでテストしています。

    リリースビルドでも再発することがあるため、解決にはなりませんでした。

    キャンセル

  • 2016/09/07 09:59

    確認です。
    メモリリークの確認方法と判断はどの様にしていますか?
    また、関数内部のコードを切り分けて動作確認はしましたか?

    キャンセル

  • 2016/09/07 11:14

    メモリリークが派手に発生するため、タスクマネージャで確認しています。
    リークする場合は、メモリを1.2Gbyteつかんだまま離しません。
    リークしていない場合は、12Mbyteほどで動作しています。

    デバッガの方はパフォーマンスツールやWindbugを利用してリークの確認をしましたが、実はリークを確認できていません。
    ※タスクマネージャ上はメモリを大量に使用しているのに、パフォーマンスツールやWindbug上にリークの痕跡がありません。

    デバッガで追う限りは、renderBitmap.Render(tempCanvas);で1.2Gbyteの増加をタスクマネージャで確認しているため、ここで確保した内部メモリが解放されていないと推測します。

    プログラム上のリークではない可能性はありますが、連続で3回ほど処理を行うと、タスクマネージャ上は3Gbyteを超えて、アプリも強制終了するため困っていました。

    キャンセル

0

リリースビルドであれば動作するので、後はデバッガなしで頑張ります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/07 09:15

    リリースビルドでも、リークがまれに発生することを確認しました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.05%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る