- PR -

【C#】参照型の参照渡しはメモリリークを起こす?

投稿者投稿内容
ベテラン
会議室デビュー日: 2005/05/16
投稿数: 85
お住まい・勤務地: 千葉県在住
投稿日時: 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重に
メモリ上に存在する可能性もあるのかな?と思い、質問させて頂きました。

ご意見・ご指摘など、宜しくお願い致します。
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-08-02 20:10
まずは、参照渡しにしている事に意味はあると思いますか?
_________________
囚人のジレンマな日々
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-08-02 20:35
引用:

梶さんの書き込み (2006-08-02 19:46) より:

やっているのが参照型の参照渡しなので
もしかしたらDataSetを代入しているところで、DataSetが2重・3重に
メモリ上に存在する可能性もあるのかな?と思い、質問させて頂きました。


なぜこれが、"なので" になるのでしょうか?

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 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 ]
ベテラン
会議室デビュー日: 2005/05/16
投稿数: 85
お住まい・勤務地: 千葉県在住
投稿日時: 2006-08-03 13:13
囚人さん、じゃんぬねっとさん、なちゃさん
返答有難う御座います。

先ず確認なのですが、DataSetは参照型ですよね?
そして、引数にRefを付けると、参照渡しになりますよね?
※ここがそもそも間違っていると、かなり恥ずかしいですね(><)

#ちなみに参照渡しに意味があるかと言われるとちょっと返答に困ってしまいますね。
 ここは既に基底クラスでそのような仕様になってしまっているので・・・

それと、検証用にデータ取得だけを行うコードを書いて
Ref引数でDataSetを渡す場合と、returnでDataSetを返す
場合とで、メモリ使用量をDevPartnerで測ってみましたが
どちらも使用量に差がない事を確認しました。
※Remotingは同じものを使っているので、Remoting先の
 メソッドに対しては、何れの場合もRef引数でDataSetを
 渡していますが・・・

この事から、DataSetをRef引数(参照渡し?)にしても
メモリリークとは関係ない・・・と結論付けて大丈夫でしょうか?
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-08-03 22:54
「ここに容器を作ってくれ」って渡すんだったら、渡す側が new することないやん。
「ここに入れてくれ」って渡すんだったら、ref にする意味ないやん。
コード:
void sampleCaller() {
	DataSet ds1 = null;
	sampleSetter1(ref ds1);

	DataSet ds2 = new DataSet();
	sampleSetter2(ds2);

	// 無意味
	DataSet ds12 = new DataSet();
	sampleSetter1(ref ds12);

	// 設計から考え直せ
	DataSet ds13 = new DataSet();
	sampleSetter12(ds13);

	// エラー
	DataSet ds22 = null;
	sampleSetter2(ds22);
}

void sampleSetter1(DataSet ref dset) {
	dset = new DataSet("setter");
	dset.Fill();
}

void sampleSetter12(DataSet ref dset) {
	dset.Fill(); // 恐いよぉ〜
}

void sampleSetter2(DataSet dset) {
	dset.Fill(); // これが普通
}


違い、わかる?

引用:

Ref引数でDataSetを渡す場合と、returnでDataSetを返す
場合とで、メモリ使用量をDevPartnerで測ってみましたが
どちらも使用量に差がない事を確認しました。


ds13 の使い方なら、差はない。


 あと、(マネージド)メモリ リークは発生しませんよ。アンマネージド リソースがリークすることはあっても。
提示されているコードだと、リークすると考えられている DataSet は“空”ですから、リークするものがないですよね?
DataSet 自身を確保しているメモリは、GC が管理していますから、Dispose しようがしまいが同じです。
Dispose は、インスタンス確保のために使用しているメモリを解放するものではありません。
インスタンスが使っているリソースを解放するためのものです。
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-08-03 23:23
手前味噌ですが。
http://blogs.wankuma.com/shuujin/archive/2006/04/08/22310.aspx

参照型を参照渡しするから、後片付けの責任のなすり合いになり、責任の所在が不明になるわけです。

_________________
囚人のジレンマな日々
未記入
ベテラン
会議室デビュー日: 2003/06/26
投稿数: 76
投稿日時: 2006-08-03 23:24


[ メッセージ編集済み 編集者: 未記入 編集日時 2007-01-19 21:49 ]

スキルアップ/キャリアアップ(JOB@IT)