- - PR -
【C#】参照型の参照渡しはメモリリークを起こす?
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2006-08-02 19:46
いつもお世話になっております。
前回の『Formを閉じる際のリソース解放について』の続きのような 質問になってしまいますが、お付き合い下さい。 以下のような処理はメモリリークを起こす可能性があるでしょうか? ※Try〜Catchは省いています --- データ取得用クラス内 public int GetDataSet(ref DataSet ds, string sqlCommand) { int ret = 0; string errmsg = ""; //Remoting先のデータ取得メソッドからデータを受け取る ret = ProxyClass.GetDataSet(ref ds, sqlCommand, ref errmsg); //エラーだった場合、エラーメッセージを表示 if(ret<0) System.Windows.Forms.MessageBox.Show(errmsg); return ret; } //データ表示Form内 private void Form1_Load(object sender, System.EventArgs e) { string sqlcommand = "・・・・(データ取得SQL構文)"; DataSet ds = new DataSet() //データ読込み int ret = DataReadClass.GetDataSet(ref ds, sqlcommand); if(ret<0) { // エラー処理 } else { grid1.SetDataBinding(ds, ds.Tables[0].TableName); } ds.Dispose(); } --- この元になったソースを、元請け会社に見せたところ「GetDataSet」の 引数の解放はいつやってるんだと指摘されてしまいました。 私としてはメソッド呼び出し元の「ds.Dispose()」で解放されている つもりなのですが、やっているのが参照型の参照渡しなので もしかしたらDataSetを代入しているところで、DataSetが2重・3重に メモリ上に存在する可能性もあるのかな?と思い、質問させて頂きました。 ご意見・ご指摘など、宜しくお願い致します。 | ||||||||
|
投稿日時: 2006-08-02 20:10
まずは、参照渡しにしている事に意味はあると思いますか?
_________________ 囚人のジレンマな日々 | ||||||||
|
投稿日時: 2006-08-02 20:35
なぜこれが、"なので" になるのでしょうか? _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||||||
|
投稿日時: 2006-08-03 00:22
まあイメージとしては、参照型の参照渡し(というよりは参照渡し?)なので、
呼び先のメソッド内で参照を入れ替えられた場合に、 元の参照先のDisposeはどうなってるの? ってことを聞いてるんだろうなとは思いますが… 最終的に呼び出し先で引数の参照をどうしてるかが分からないので、 なんともいえないですが…というか、 最終的にはRemotingを使ってるようですから、本当に参照の行方が どうなっているかを追おうとすると泥沼にはまります。 ※この辺、通常のメソッド呼び出しとRemotingで整合性が取れない部分です。 なので、DataSetなんかの明らかにアンマネージリソースがないオブジェクトに関しては、 無理にDisposeを完全に実行しようとするのはあきらめた方がいいと思います。 この部分に関してはIDisposableなので必ずDisposeするというような ルールからは例外として扱ったほうが無難でしょう。 ※はっきり言ってMarshalByValueComponentとRemotingでの refやoutの引数とDisposeは相性が悪いというか… 値型という考え方とIDisposableが相性悪いともいえますが。 ※あとはまあ、少なくともRemotingの部分に行くまではrefは本当は必要ないでしょうね。 Remotingの部分でもoutでいい気はしますが。 あとメモリリークというのは誰かが何か勘違いしてたりしますか? 実質問題がない部分に悩んだり時間をとられるよりは、 本当に問題が発生する可能性のあるところを気にするほうが 現実的だと思います… [ メッセージ編集済み 編集者: なちゃ 編集日時 2006-08-03 00:37 ] | ||||||||
|
投稿日時: 2006-08-03 13:13
囚人さん、じゃんぬねっとさん、なちゃさん
返答有難う御座います。 先ず確認なのですが、DataSetは参照型ですよね? そして、引数にRefを付けると、参照渡しになりますよね? ※ここがそもそも間違っていると、かなり恥ずかしいですね(><) #ちなみに参照渡しに意味があるかと言われるとちょっと返答に困ってしまいますね。 ここは既に基底クラスでそのような仕様になってしまっているので・・・ それと、検証用にデータ取得だけを行うコードを書いて Ref引数でDataSetを渡す場合と、returnでDataSetを返す 場合とで、メモリ使用量をDevPartnerで測ってみましたが どちらも使用量に差がない事を確認しました。 ※Remotingは同じものを使っているので、Remoting先の メソッドに対しては、何れの場合もRef引数でDataSetを 渡していますが・・・ この事から、DataSetをRef引数(参照渡し?)にしても メモリリークとは関係ない・・・と結論付けて大丈夫でしょうか? | ||||||||
|
投稿日時: 2006-08-03 22:54
「ここに容器を作ってくれ」って渡すんだったら、渡す側が new することないやん。
「ここに入れてくれ」って渡すんだったら、ref にする意味ないやん。
違い、わかる?
ds13 の使い方なら、差はない。 あと、(マネージド)メモリ リークは発生しませんよ。アンマネージド リソースがリークすることはあっても。 提示されているコードだと、リークすると考えられている DataSet は“空”ですから、リークするものがないですよね? DataSet 自身を確保しているメモリは、GC が管理していますから、Dispose しようがしまいが同じです。 Dispose は、インスタンス確保のために使用しているメモリを解放するものではありません。 インスタンスが使っているリソースを解放するためのものです。 | ||||||||
|
投稿日時: 2006-08-03 23:23
手前味噌ですが。
http://blogs.wankuma.com/shuujin/archive/2006/04/08/22310.aspx 参照型を参照渡しするから、後片付けの責任のなすり合いになり、責任の所在が不明になるわけです。 _________________ 囚人のジレンマな日々 | ||||||||
|
投稿日時: 2006-08-03 23:24
[ メッセージ編集済み 編集者: 未記入 編集日時 2007-01-19 21:49 ] |