- PR -

変数に対するメモリの使い方について

投稿者投稿内容
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-06-12 21:41
引用:

MIRUさんの書き込み(2006-06-11 18:18)より:

正直、皆さんの回答の半分ぐらいしか理解できない状態です。(特にDispose()… )
どうやら私は、まだこの質問をしていい段階にきていなかったようです。


今疑問に思っているのに、今を逃したら、何時学ぶのですか?

 Dispose は、何も「解放」だけを取り扱いません。これには、「適当に処置する」という意味があります。
使用することを終わったために“後片付けを適切に行う”ととらえれば、
何もメモリを解放することにこだわることがなくなりませんか?
 IDisposable インターフェイスは able (することが出来る)なのですが、実際には「後始末が必要」という宣言であり、後始末の仕方は、それぞれに任されています。


 あと、囚人さんが軽く触れられていますが、
変数はスコープを外れたときに解放(する準備が)されます。
したがって、PostBack が発生するより前に、解放(する準備が)されます。


おまけ:
 IDbConnection インターフェイスを実装するクラスでは、Close によって接続がコネクション プールへ返されます(返すように実装しなければなりません)。msdn には、
引用:

SqlConnection は、適用範囲外では閉じられません。そのため、 Close または Dispose を呼び出して、明示的に接続を閉じる必要があります。

OleDbConnection は、適用範囲外では閉じられません。そのため、 Close または Dispose を呼び出して、明示的に接続を閉じる必要があります。

OracleConnection オブジェクトが適用範囲外になる前に、必ず Close または Dispose を呼び出して、開いている OracleConnection オブジェクトを明示的に閉じる必要があります。


とあるので、Dispose と Close が等価であると期待できます。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-06-12 23:54
引用:

渋木宏明(ひどり)さんの書き込み (2006-06-12 21:35) より:

単純に「どちらか」は選べないです。
「そのクラスの終了処理として何が適切か」はクラス仕様が規定します。
Close() と IDisposable.Dispose() が等価でないクラス実装も存在する(存在し得る)ので、「常に選択が可能」と考えるのは良くないと思います。


等価でない場合でも、Dispose メソッドが Close メソッド未満であるものはないと思います。
これについては、何か心あたりのあるものは存在しますか? (逆はあります)

私は、等価でない場合、Dispose は Close + α であるべきだし、実際そうなのだと思っています。

引用:

例外を throw したクラスインスタンスが、IDisposable.Dispose() 以外の操作を受け付けることを期待していないからです。


これに関しては、このレスで意味がわかりました。

最も身近な例をあげると、Transaction の都合ですね?
これを考慮していて finally 句に記述すると、当然 catch 句での処理も必要になる。

ということですね。

引用:

その場合、finally 節内の Close() が例外を発生することも考慮しなくてはならず、コード量が増大します。


ついでに、ここでもコード量も当然増加する...

引用:

using 句は、隠蔽されている IDisposable.Dispose() も呼び出します。


も、もちろん、それは当然知っています。(;^-^)
(知っていなかったら、その IDisposable インターフェイスの話が一切できないw)

これに関しては、VB7.1 以前の都合によるお話です。(Using がないので)
Jitta さんからも少し話が出ているように、Close メソッドだけで良いハズなのですね。

引用:

てか、個人的には IDisposable.Dispose() は「必ず」隠蔽して実装することにしておけば、余分な混乱が避けられたのではないかと思います。


+ VB7 の時点で Using をサポートしていれば、じゃないでしょうか? (w
この場合、Close メソッドを保証したくなって、現状とは違った意味で混乱するでしょうし、
逆に、Dispose メソッドに委ねる方針へ統一する場合は、C# 以外の言語で面倒なことにw

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2006-06-13 08:52
引用:

等価でない場合でも、Dispose メソッドが Close メソッド未満であるものはないと思います。
これについては、何か心あたりのあるものは存在しますか? (逆はあります)



未満と呼ぶべきかどうか分からないですが、ODP.NET の Close()/IDisposable.Dispose() の実装は今まで見たことが無いパターンですね。

元々 IDisposable.Dispose() はアンマネージリソースの解放タイミングを最適化するだけのために設けられたものなので、Dispose() メソッドにあまり大きな期待をよせるのには抵抗を感じます。

大きな声では言えませんが、システムに余裕がある状況で正常系だけを考えるなら、Dispose() 呼び出しをサボたって構わないくらいの位置づけだと思います。

往々にして「Dispose() は Close() メソッド以上である」と期待できる/したいというのには賛成ですが、「あんなの」が実在しているのを見ると、やはり過度の期待(すべてのクラスは適切に実装されている、等)は危険に思えます。

もちろん、ドキュメントなどでクラス仕様として Dispose() が Close() 相当以上の動作をすると説明されてる場合、その動作をあてにしたコードを書くのはまったく問題ないと思います。

引用:

using 句は、隠蔽されている IDisposable.Dispose() も呼び出します。



「も」じゃなくて「をも」ですね。
意外と知らない人がいるので一応念のため (^^;

よく try ~ で「using と等価なコード」を示すことがありますが、そういう場合も IDisposable へのキャストを省略しないで Dispose() 呼び出しを記述して欲しいです。

引用:

+ VB7 の時点で Using をサポートしていれば、じゃないでしょうか? (w



んー、いまさら後戻りもできないし。。。

Avalon や Indigo の初期実装では、IDisposable.Dispose() 実装は隠す方向みたいでしたが、最終的にはどうなったのかな?

Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-06-13 19:25
引用:

Jittaの書き込み(2006-06-12 21:41)より:

 IDbConnection インターフェイスを実装するクラスでは、Close によって接続がコネクション プールへ返されます(返すように実装しなければなりません)。


根拠を忘れてた。IDbConnection.Close メソッドの説明より。
引用:

Close メソッドが、保留中のトランザクションをロールバックします。次に、接続を接続プールに解放します。接続プールが無効の場合は接続を閉じます。



 COM 呼び出しの場合、Dispose は存在しないことがあります。つまり、Dispose だけが「後始末」ではない、といえるでしょう。
 このことから、渋木宏明(ひどり)さんの「クラスの仕様をドキュメントで確認して、適切な方法で終了処理を行いましょう」に賛成です。
 イコール、IDispose を実装する場合、ドキュメントを整備する必要がある、と。
MIRU
常連さん
会議室デビュー日: 2006/05/30
投稿数: 21
投稿日時: 2006-06-13 21:18
半ば放置のような形になって申し訳なく思っております……。
レスの早いに、私の理解力がまったく追いついていない状況です。

引用:

例えば以下のような、Dispose しないメソッドを書いて、 2 回続けて呼び出してみて下さい。



これの例を試したところ、ファイルに排他がかかりました。
コメントを外した場合は、ちゃんと処理が通りました。

そして、皆さんの投稿に変数の話題がほとんどないことから考えますと

Disposeはコネクションのリソースを解放するのが一般的な使い方で、
私が勝手に期待していた、Disposeを付けるとその変数に対して使用されていた
(メモリなりリソースなりの)領域がその処理が走ったタイミングで
解放されるということは無い

ということでしょうか?
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-06-13 23:11
引用:

MIRUさんの書き込み (2006-06-13 21:18) より:

Disposeはコネクションのリソースを解放するのが一般的な使い方で、私が勝手に期待していた、Disposeを付けるとその変数に対して使用されていた(メモリなりリソースなりの)領域がその処理が走ったタイミングで解放されるということは無いということでしょうか?


「メモリ」 が解放されるタイミングは、ファイナライザです。
つまり、GC が回収しに来た時です。
ファイナライザは、明示的に呼び出さない限りは、タイミングを予想したり期待することはできません。

逆を言えば、「無い」 とは言い切れないですね。

# '瞬間的' な話であれば、コンピュータの世界では「無い」ですけど。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2006-06-13 23:28
引用:

じゃんぬねっとさんの書き込み (2006-06-13 23:11) より:
「メモリ」 が解放されるタイミングは、ファイナライザです。
つまり、GC が回収しに来た時です。
ファイナライザは、明示的に呼び出さない限りは、タイミングを予想したり期待することはできません。


いや、GCとファイナライザは別に理解した方がいいでしょう。
普通ファイナライザでメモリが開放されるとは言いませんし、
ファイナライザを明示的に呼び出すことも普通はできません。

MIRUさんの言っているメモリの開放というのは、おそらく参照の開放の
つもりで言っているのでしょうから、そういう意味では明示的にnull(Nothing)を
メンバにセットしたときなどがそれにあたるといえます。

本当の意味(というのも微妙な表現ではあります)でメモリが開放というか
再利用可能な状態になるのは、GCのタイミングということになります。
MIRU
常連さん
会議室デビュー日: 2006/05/30
投稿数: 21
投稿日時: 2006-06-14 22:19
>じゃんぬねっとさん、なちゃさん
どちらかというと、Disposeは「メモリ開放予約」みたいな意味なのですね。

今までは、使い終わった変数には、手当たりしだいnothingを代入して、
「あぁ、これでメモリが開放された」とか思っていましたが、
今後はもう少し考えて、処理を行っていこうと思います。

皆さんのお陰で、GCやリソースというものに対して知ることが出来ました。
今後も、もう少し自分で調べてみようと思います。ありがとうございました。

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