
C#のメモリ解放についてご教授ください。
以下の例のAAAクラスで、CCCクラスのListを破棄およびメモリ解放するにはどのようにすれば良いでしょうか。
null代入だけで解放されるのでしたら御の字なのですが・・・。
※newはあまり好ましくありません。
例)
class AAA{
BBB b;
AAA(){ b = new BBB(); }
add(string s){ b.add(s); }
clear(){ ※ここでCCCクラスのListデータを破棄し、メモリ解放されるようにしたい。 }
}
class BBB{
CCC c;
BBB(){ c = new CCC(); }
add(string s){ c.add(s); }
}
class CCC{
List<string> list;
CCC(){ list = new List<string>(); }
add(string s){ list.add(s); }
}
No.4ベストアンサー
- 回答日時:
>clearはAAAで問答無用で削除ならチェック不要という考えがありました。
すみません誤解していました。clearはAAAが持つインスタンスの参照を手放すのですね。
それなら、nullチェックは不要です。
ちなみに、C#では「インスタンスの参照を手放す」=「メモリが解放される」ではありません。
あくまでBBBのインスタンスたるbをもう使えなくなるというだけで、
インスタンスがいつ破壊される(メモリが解放される)かはユーザにはわかりません(GCのお仕事)。
で、ここから誤解だといけないのですが、先に回答したように
BBBがCCCやDDDをコントロールする、AAAはBBBを通じてのみそれを行う…
という理解でいいんですよね?(そういう意味でMediatorという言葉を使いました)
ならば、AAAがCCCやDDDの内部を知ってしまうのはどのような意味でも良くないでしょう。
クラス階層をわざわざ破壊するようなことはすべきではないです。
>BBBからCCCデータなどを消し、AAAに戻ってきて改めてBBBを消すという流れは無駄を感じていたため
それを無駄と感じるのは
・実は不必要なクラス設計にしている
・クラス階層の必要性についての理解に乏しい
のどちらかだと思います。
何事にも例外はありますが、今回のケースは例外扱いするメリットが感じられないです。
すみません、遅くなりました。
あれから設計見直しが入りました。
CCCのポジションにあたる処理が、実際はファイル読み込み、解析、抽出を行うような処理で、そこそこ時間がかかる兼ね合いで、AAAを呼び出すアプリ側がその間動かなくなるのは困る、という話になり、BBBでスレッド処理からCCCを呼び出すことになりました。
また、これによりAAAの呼び出しをアプリ側が複数回したいということになり、CCCのインスタンスは複数個持ち、clearは指定されたもののみに変更となったため、BBBでCCCの精査を行う必要がでたため、clearはAAAでのBBB破棄からかわることとなりました。
何度もご解答ありがとうございました。
No.6
- 回答日時:
質問のソースを見る限りでは
b=new BBB();
が最もまっとうでしょうね。
bの差していた古いBBBのインスタンスは、それが抱えている
ものも含めて、いずれGCされます。
BBBをnewするだけでメモリを馬鹿食いする設計なのでしょうか?
もしそうなら
b=null;
でも仕方ないですが、bのnullチェックコ―ドがクラス全体に蔓延して
汚ならしいコードになるのでご注意を。私なら見直します。
それからGC.collectは超遅いので、細かな処理の中に散りばめたりしないこと。
全く使わないことを強く推奨します。
No.5
- 回答日時:
クラスAAA内で、
public void Clear() { b = null; }
としただけではクラスBBB、クラスCCCおよびクラスCCC内のlist変数はメモリ解放されません。
ガベージコレクタが走行した時に初めて解放されます。
これはデストラクタに何かコードを書いてみれば分かります。
b = null;としただけでは、BBBクラス、CCCクラスともにデストラクタは走行しません。
明示的なメモリ解放が必要ならば、ガベージコレクタを明示的に実施する必要があります。
GC.Collect();
余談ですが、よく経緯を分かっていないのでよく分からないんですが、
AAAクラスをインスタンス化する前に、AAAクラスのClear()メソッドは呼べないと思うんですが。
それと、AAA.Clear()後に、AAA.Add()をしたら死にますね。
public void Add(string s)
{
if (b == null) b = new BBB();
b.Add(s);
}
となっていなければ。
もしくは、AAAクラスがBBBクラスやCCCクラスに依存する形ならば、AAA.Clear()を実施した時に、
Add()している値だけがクリアされ、クラスインスタンスまで破棄されてはならないという仕組みになりませんかね?
必要になった時、都度BBBクラス、CCCクラスインスタンスが新たに作られるのはコスト高くありませんか?
AAAクラス、BBBクラス、CCCクラスの設計を見直された方がよいのでは。
No.3
- 回答日時:
確認ですが、AAAがインスタンスを作っているのはBBBクラスだけなんですよね?
それだったらCCCとDDDのどちらかだろうが、両方だろうが、
AAAがそのことを知るべきではなく、CCCとDDDを扱っているBBBの責任で面倒見るべきです。
そうなっていないのなら、クラス構造から見直したほうがいいです。
>ユーザーがインスタンス生成前にclearを呼ぶと、
インスタンス生成とインスタンスへのアクセスが前後する可能性があるなら、nullチェックは必須でしょう。
CCCとDDDの面倒はBBBが見るのですから、BBBのインスタンスができているかどうかチェックすれば足りるはずです。
>AAAでbをnullすれば
元のご質問はCCCクラスのListオブジェクトを破壊したいということだったかと思いますが、
おっしゃるようにすればAAAはBBBクラスのオブジェクトをすべて手放します。
それでご希望にかなってます?
回答ありがとうございます。
〉インスタンス生成とインスタンスへのアクセスが前後する可能性があるなら、nullチェックは必須でしょう。
→やはりnullチェックした方がいいですか・・・。add側でチェックする気はあったのですが、clearはAAAで問答無用で削除ならチェック不要という考えがありました。予定ではBBBインスタンスも含めた完全削除を考えていたため、BBBからCCCデータなどを消し、AAAに戻ってきて改めてBBBを消すという流れは無駄を感じていたため、AAAのみでデータ破棄、メモリ解放が完結させられるならそうしたかった、という気持ちです。やはりこういう場合でも、BBBでCCC削除などを実施した方がよいのでしょうか?
No.2
- 回答日時:
No.1です。
>①AAAは呼び出し元クラスのIFの立ち位置として、実処理を置きたくなかった。
その設計は良いと思います。
さらに言えばAAAは「実処理は同実装されているか」も知らなくて
②本来CCC以外にDDDなどがあり、BBBでどのインスタンス生成を行うかなどの分岐があります。①の都合により、BBBを連携用として作っています。
ああ、じゃ、BBBはMediatorの役割なのですね。
AAAは実際に使われているのはCCCなのかDDDなのかわからないという理解でいいでしょうか?
であれば、なおのことCCCのメンバーデストラクトはBBBの役割で、
AAAから直接CCCをコントロールすべきでないと思います。
AAA.clear()は単純にBBB.clear()を呼んで、
実際は何をすればいいのかはBBBに任せるように設計すべきかと思います。
回答ありがとうございます。
確かにBBBでという考えも分かるのですが、CCC、DDDのどちらかを消したいという主旨ではなく、CCC、DDD含め、完全消去をしたいのです。
で、ここも伝え漏れなのですが、本来はAAAでBBBをnewするのはコンストラクタではなく、別場所になります。ですので、ユーザーがインスタンス生成前にclearを呼ぶと、インスタンスが無いの事象が発生します。かといって、clearでインスタンスがあるかチェックとかも避けたいところがあるので、問答無用でAAA内で全てを捨てたい、という考えのもとの結果が今になります。
話が戻って恐縮ですが、先の質問お礼にも挙げたnull代入については、AAAでbをnullすれば良いの解釈でよろしかったでしょうか?
何度もすみません。
No.1
- 回答日時:
Listは参照型ですから、null代入すれば参照を手放し、メモリはガベージとなっていずれGCに掃除されます。
でも、class BBBを飛ばしてclass AAAにやらせたいのですか?
現在はAAAはCCCがListを使っていることなんて知らないし、それどころかCCCの存在も知らないですよね。
Listをインタフェースとして見せるようにすればAAAからやるのも可能でしょうが、
現在の(それなりに)疎結合になっているクラス間依存を一気に大きくしてしまう気がします。
Listの開放はCCC自身にやらせて、BBB(を経由してAAA)にインタフェースを提供するほうがデザイン的にはいいと思います。クラス間依存も複雑になりませんし。
回答ありがとうございます。
null代入というのは、AAAでbにnullを入れればという解釈でよろしかったでしょうか?
例について、AAA→BBB→CCCといった作りになっているのは、以下の要因からです。
①AAAは呼び出し元クラスのIFの立ち位置として、実処理を置きたくなかった。
②本来CCC以外にDDDなどがあり、BBBでどのインスタンス生成を行うかなどの分岐があります。①の都合により、BBBを連携用として作っています。
本質問の意図を伝えるために省いたり、作り替えたりしてる部分が多々ありました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) ¥マークを含むパスの処理について(マクロ、または関数) 2 2022/12/25 02:11
- C言語・C++・C# クラスのメンバ変数を基準に並べ替えをしたい 5 2022/12/25 17:40
- SQL Server ACCESSで3ファイルを結合して、表を作成するやり方を教えて下さい。 17 2022/08/15 20:34
- Perl perl このテキストファイルを簡単に配列に入れるには? 2 2022/04/27 20:24
- PHP style.cssのjQuery条件付きcssが機能しない 4 2022/07/17 18:27
- SQL Server ACCESSで複数テーブルを結合して、リストを作る方法を教えてください。 2 2022/08/12 19:32
- PHP アコーディオンPHPが上手くいかない 3 2022/07/15 16:29
- JavaScript JavaScript|特定URLだった時、特定の要素を変更するコードの書き方を教えてほしいです 2 2023/08/25 21:43
- SQL Server ACCESSで表が作りたく、そのためのSQL文や設定方法を教えてください。 1 2022/08/15 12:28
- Java java final 1 2022/06/10 22:49
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ファイル読み込み/書き込み速度...
-
C#「オブジェクト参照が必要で...
-
newしないインスタンス?実体化...
-
C#の構造体の開放のしかた
-
private static という変数の修飾
-
オブジェクト参照がオブジェク...
-
Form1上にあるTextBox1を Modul...
-
servletのマルチスレッドとはど...
-
そんなにお金がなくても年に1度...
-
今日は こどもの日 で、良い天...
-
EXCEL VBAにて動的にCheckBOXを...
-
DBunitの期待値についての質問...
-
「タイプ初期化子が例外をスロ...
-
0歳児の指しゃぶりに関して
-
BMP画像を画像処理して連続に表...
-
エクセルVBAで、条件に一致する...
-
恋愛
-
DirectXのスプライト機能で3D回転
-
VBAでの[]
-
C++BuilderのMemoコンポーネン...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
private static という変数の修飾
-
変数名の付け方
-
複数の変数を宣言する時、同時...
-
インスタンス参照でアクセスで...
-
C# インスタンスの破棄
-
C#において、同じインスタンス...
-
オブジェクト参照がオブジェク...
-
生成したインスタンスを削除す...
-
VB.NET getとsetの概念がわかり...
-
javaのクラスの作り方、エラー...
-
変数の参照でエラーが出てしま...
-
「インスタンス」の意味をわか...
-
インスタンスを同じ名前で作成...
-
newしないインスタンス?実体化...
-
フォームの存在をチェックする方法
-
String a = "a"; と String b =...
-
C#のメモリ解放についてご教授...
-
vb.netでFAXを送信する方法
-
他のファイルの変数参照
-
Delphiでインスタンスが作成さ...
おすすめ情報