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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

メモリリーク

メモリリークは、プログラムファイルがメモリの解放に失敗した時に起こります。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

3回答

9948閲覧

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

SKawaguchi

総合スコア10

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

メモリリーク

メモリリークは、プログラムファイルがメモリの解放に失敗した時に起こります。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

1クリップ

投稿2016/09/06 05:06

編集2016/09/07 00:14

###前提・実現したいこと
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の追加とファイルを用意していただければ、コピペで動作します。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

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

投稿2016/09/06 06:47

SKawaguchi

総合スコア10

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SKawaguchi

2016/09/07 00:15

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

0

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

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

投稿2016/09/06 06:29

TAKAYASU

総合スコア146

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SKawaguchi

2016/09/06 06:45

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

2016/09/07 00:13 編集

リリースビルドでもまれにリークが発生するようです。 ※デバッグビルドだと、今のところ100%再現します。 上記関数は、WPFアプリケーションのスケルトンを作成後、Window_Loaded()イベントを追加してその中でfunc()を呼んでテストしています。 リリースビルドでも再発することがあるため、解決にはなりませんでした。
TAKAYASU

2016/09/07 00:59

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

2016/09/07 02:14

メモリリークが派手に発生するため、タスクマネージャで確認しています。 リークする場合は、メモリを1.2Gbyteつかんだまま離しません。 リークしていない場合は、12Mbyteほどで動作しています。 デバッガの方はパフォーマンスツールやWindbugを利用してリークの確認をしましたが、実はリークを確認できていません。 ※タスクマネージャ上はメモリを大量に使用しているのに、パフォーマンスツールやWindbug上にリークの痕跡がありません。 デバッガで追う限りは、renderBitmap.Render(tempCanvas);で1.2Gbyteの増加をタスクマネージャで確認しているため、ここで確保した内部メモリが解放されていないと推測します。 プログラム上のリークではない可能性はありますが、連続で3回ほど処理を行うと、タスクマネージャ上は3Gbyteを超えて、アプリも強制終了するため困っていました。
guest

0

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

投稿2016/09/06 05:48

tamoto

総合スコア4103

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SKawaguchi

2016/09/06 05:52

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問