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

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

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

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

Q&A

解決済

2回答

12884閲覧

C# usingの中で定義した変数は、usingの終了後メモリは破棄されるのですか?

GiveAHand

総合スコア286

C#

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

0グッド

0クリップ

投稿2016/07/27 05:14

forループの中で、連続してクラスをnewすると、newするたびにメモリが増える事を知りまして、メモリ増加を防ぐなら、usingか、処理終了時にDisposeをする事を知りました。

なので、メモリ増加に神経質になっているのですが、基本的に、変数、構造体の場合は、関数終了と同時にメモリは破棄されると思うのですが、ループの中で何度も定義した場合はどうなるのでしょう?

例えば、

C#

1for(i = 0;i<100;i++){ 2 3 string aaa = ""; 4 5 // aaaを使った処理 6 7}

このような場合、ループのたびにstringが生成されて、メモリは増加してしまうのでしょうか?
メモリの事を考えたら、

C#

1 2string aaa = ""; 3 4for(i = 0;i<100;i++){ 5 6 // aaaを使った処理 7 8}

このほうがいいでしょうか?

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

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

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

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

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

guest

回答2

0

ベストアンサー

メモリ増加を防ぐなら、usingか、処理終了時にDisposeをする事を知りました。

ちょっと間違ってます。

基本的に、変数、構造体の場合は、関数終了と同時にメモリは破棄されると思うのですが

間違ってます。


C#のメモリ管理はガベージコレクタ(GC)によって行われますが、
GCがメモリを開放するタイミングは、ざっくり
「対象オブジェクトが使われなくなった後に、必要に応じて」です。

C#

1string a = "Hoge"; // <- メモリ上に確保される 2/* 3何か処理 4*/ 5Console.WriteLine(a); // ここで最後にaを使った。 6//ここからaがメモリ上で生死不明になる 7/* 8何か処理 9*/

(.NETが管理している分の)メモリはGCが自動で管理してくれますが、
その他のリソース、例えばファイルとかは自動で管理してくれないので、
usingとかDisposeで開放します。

なのでDisposeが実装されているクラスを使い終わったら
Disposeしたほうがいいのは当然なのですが、別にメモリのためとは限りません。

そしてDisposeしたかどうかと.NET管理メモリ上に存在するかは別問題です。
例えばSerialPortというシリアル通信のためのクラスがあるのですが、
こいつはOpen()で接続を開始して、Close()で終了します。
同じインスタンスで何度もOpen()->Close()->Open()->...できます。
で、Close()は内部で自身をDispose()してます。


usingの中で定義した変数は、usingの終了後メモリは破棄されるのですか?

(.NET管理のメモリは)されますが、直後ではありませんし、usingの効果でもないです。

forループの中で、連続してクラスをnewすると、...

足りなくなったら開放するのでどちらでも問題無いです。
(そもそも最適化によって中に書いても外に置かれるかも)

投稿2016/07/27 05:41

編集2016/07/27 05:59
ozwk

総合スコア13521

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

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

GiveAHand

2016/07/27 07:09

ozwk様 非常に丁寧なご回答ありがとうございます! なるほど、よく理解できました。 そういう事なんですね。。。 あまりにも自分の理解が出来ていなくて、驚くほどですが、だいぶ自信がもてました。 ありがとうございました!
guest

0

こんにちは。
この質問にはいくつかポイントがあるので、分けて回答します。

まずはstring型を使っている質問のコード例について回答します。
C#の中でstring型は少し特殊な存在で、一般的なクラスとメモリの扱い方に違いがあります。
質問のコードの場合であれば、「上と下、どちらで書いてもメモリ使用量には影響しない」と断言できます。

次に、一般的なクラスをnewした場合について。
C#はガベージコレクションを採用している言語であり、基本的にコード上で「メモリの解放を直接指示することはない」ということは理解していますか?
「forループの中でnewする度にメモリが増える」は半分正しいですが、その後ろに「1ループする度に、newしたクラスは自動解放待ちになるので気にする必要はない」と付きます。もちろんどこかに参照を保持していないことが前提ですが。
結論としては、「一時的にメモリ使用量が増えているように見えますが、大半は解放待ち状態に入っているので気にする必要はない」です。質問にあるような、「一つのインスタンスを最初に宣言して使い回す」というのは新しいメモリを確保しない分は多少メモリにやさしいですが、バグが潜みやすいコーディングスタイルなのであんまりオススメできません。本当にメモリを注視しなければならない場面でのみ検討するべきです。そんな場面になったらむしろunsafeが視野に入るレベルですが……

最後に、usingDispose()について、多少勘違いがあります。
この2つは、IDisposableインターフェイスに関わる構文です。このインターフェイスは「インスタンスを使用しなくなった時、明示的に終了処理ができる」ことを表すものです。よって、これはメモリの解放と直接の関係はありません。どのようなクラスであっても、そのスコープ外に出てしまえば、そのまま放置することでGCによって自動でメモリが解放されていきます。
しかし、IDisposableは特にメモリと深く関連付けられて話題にされることが多いです。IDisposableが重要な理由は、「C#ではGCによってメモリが解放されるが、"何時"解放されるかはわからない」という点です。例えば、何かファイルをオープンした時などは、使い終わって放置すれば"何時かは"解放される、と言うのが良くない理由はわかっていると思います。よって、そういう場合に明示的に終了処理を呼び出すためにあるのがIDisposableなのです。
結論としては、「IDisposableが実装されたクラスは必ず使用後にDisposeする、またはusingで使う」「IDisposableが実装されていないクラスはなにも気にせず使う」って感じで大丈夫です。

投稿2016/07/27 06:06

tamoto

総合スコア4105

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

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

GiveAHand

2016/07/27 07:11

tomato様 非常jにわかりやすくて丁寧なご説明、ありがとうございます! なるほど、そういう事なんですね。。。 私は、あまりにも理解が出来ていませんでした。 でも、これでだいぶクリアになりました。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問