投稿数 - 437, コメント - 59536, トラックバック - 156

再び、Dispose していいのかどうか悩むべき。

@IT会議室より

Dispose していいのかどうか悩むべき

上記の記事に非常に有意義なコメントを書いてくれた人がいるので紹介する。是非コメント欄を読んで頂きたい。こういうコメントを書いてくれる人は大歓迎だ。私の記事を読んで「こいつアホな事を偉そうに言ってるな!」と思ったら、どしどし未熟な私に意見して欲しい。忌憚ない意見ほど有難い。
#でも、少々白熱したので気分を害したなら申し訳ありません。懲りずに再びコメントを書いてくれると非常に嬉しい。

 

Dispose パターンは単純にはいかない。GC を備えた CLR はメモリの面倒はみてくれるが、それ以外のリソースの面倒は我々がみなければならない。リソースは GC に任せてれば良いとか、IDisposable を実装しているなら兎に角 Dispose を呼べというスタイルでは駄目な事は明白である。

最も大事な事は「Dispose していいのかどうか悩む事」。

先ず、自分で生成し、且つ非常に寿命が短いインスタンスは Dispose してよい事がほぼ明確にわかる。勿論ドキュメントを読んで判断する事。

次に、自分で生成していないが、非常に寿命が短いインスタンスは Dispose してよい事があまり明確ではないが、多分 Dispose して良い。勿論ドキュメントをよく読む事。

その次に、自分で生成したが、寿命が長いインスタンスは Dispose してよい事が殆ど明確ではない。こういった寿命が長くなりがちなインスタンスのリソースは早々に破棄しなくてもよいリソースだったりする。少々寿命が長くても困りはしないだろう。GC に任せてもよいと思う。勿論ドキュメントをよく読む事。

最後に、自分で生成していないが、寿命が長いインスタンスは Dispose してよい事がまるで明確ではない。誰が管理しているのかも分からなくなる。このような場合は殆どにおいて GC に任せるしかない。また、設計が誤っていないか見直そう。勿論ドキュメントをよく読む事。

投稿日時 : 2007年2月1日 22:40

フィードバック

# re: 再び、Dispose していいのかどうか悩むべき。

「寿命」は判断材料にはならないと思いますが。。。
「所有権」を意識するのが、イチバン間違いないと思います。

2007/02/01 23:07 | 渋木宏明(ひどり)

# re: 再び、Dispose していいのかどうか悩むべき。

>「寿命」は判断材料にはならないと思いますが。。。

寿命が長いと、他がそのインスタンスの参照をとっている可能性が高まって所有者が複数いるかもしれないと考えました。
でも、それが「所有者」の意識ですね。
2007/02/01 23:11 | 囚人

# Dispose

Dispose
2007/02/01 23:50 | 中の技術日誌ブログ

# re: 再び、Dispose していいのかどうか悩むべき。

寿命は関係なく所有意識ですね。

前回の「SqlCommand.ExecuteReader メソッド」は取り上げるにはいい例でしたね。
私としてはHELPをもっとちゃんとしてほしいです。
でも、そういう意味では「SqlDataReader を構築します。」ときちんと書いてありますのでまぁまぁかなと思います。
それよりも問題なのは使用例ですね。
SqlConnectionだけusingしているのでそれでいいんだと思う初心者がいっぱい出そうです。

前回コンストラクタで必ず生成させるようにするという案を出されていましたが、いくつかののGOFパターンの否定と受け取られかなないので、そこまでは行かなくても、生成したインスタンスを自分はDisposeしないで返しているということをイメージできるメソッド名にしておくくらいでしょうね。
2007/02/01 23:59 | えムナウ

# re: 再び、Dispose していいのかどうか悩むべき。

Reader と Command の Dispose 忘れには1回はまりましたね。(^^:)
2007/02/02 0:38 | オノデラ

# re: 再び、Dispose していいのかどうか悩むべき。

先日まで「とにかくDispose」だと思っていましたが、打ちのめされました。
#SystemBrushesのバカ。
2007/02/02 0:59 | シャノン

# Close が Dispose 呼ぶのが気に食わない

Close が Dispose 呼ぶのが気に食わない
2007/02/02 2:01 | へぼろっぱぁ

# Close が Dispose 呼ぶのが気に食わない

Close が Dispose 呼ぶのが気に食わない
2007/02/02 2:02 | へぼろっぱぁ

# re: 再び、Dispose していいのかどうか悩むべき。

Close() が「必ず」Dispose() を呼ぶわけでもありません。
Close() が Dispose() のエイリアスである「場合がある」だけです。
2007/02/02 9:37 | 渋木宏明(ひどり)

# re: 再び、Dispose していいのかどうか悩むべき。

Close() が Dispose(false)を呼び出す(アンマネージドリソースの解放)のを推奨しているのであって、
逆に言うとOpenでアンマネージドリソースを確保しろと言っているわけです。

Open->Close->Openは可能であるべきです。
2007/02/02 10:24 | えムナウ

# re: 再び、Dispose していいのかどうか悩むべき。

>中さん、えムナウさん
確かに寿命というと関係ありませんね。スコープと言った方がよかったかもしれません。
スコープが広い(寿命が長い)と間違えました。
スコープが広いと参照が増えて、所有者が多くなりややこしくなります。

>前回コンストラクタで必ず生成させるようにするという案を出されていましたが、いくつかののGOFパターンの否定と受け取られかなないので、そこまでは行かなくても、生成したインスタンスを自分はDisposeしないで返しているということをイメージできるメソッド名にしておくくらいでしょうね。

生成系のデザインパターンと IDisposable を併用するのは工夫が要りますね。策としてはメソッド名を明確にするぐらいですね。

>オノデラさん、シャノンさん
誰もが一度は通る道です^^;

>THREE-ONEさん
トラックバック有難うございます。
「IOpenable」。確かにあれば良いかも^^;
2007/02/02 12:41 | 囚人

# re: 再び、Dispose していいのかどうか悩むべき。

所有者は増えません。常に一人です。
所有者に見えたとしても、他は全部「借用者」です。

ただし、「委譲」パターンでは所有者が移り変わります。

Java には ICloseable ってのがありますね。
後始末云々に注目するなら、Open を強調するよりも Close() を強調するべきでしょうね。


2007/02/03 23:18 | 渋木宏明(ひどり)

# re: 再び、Dispose していいのかどうか悩むべき。

>所有者は増えません。常に一人です。
>所有者に見えたとしても、他は全部「借用者」です。

「借用者」。お~!それはいい表現ですね。
2007/02/04 13:24 | 囚人

# re: 再び、Dispose していいのかどうか悩むべき。

みんな難しく考えすぎなんじゃないかなー
IDisposable.Dispose() は、アンマネージリソースを扱うクラスが異常な状態に陥っていても finally や Finalize() でアンマネージリソースの解放を保証するための一種の「安全装置」と考えれば気が楽になるはずですよ。
2007/02/05 10:37 | 渋木宏明(ひどり)

# re: 再び、Dispose していいのかどうか悩むべき。

安全装置でしかない、と考えると、C++的プログラマ万能論になってしまうのでは。
言語での制約などでEoD的な方向に転べばいいな、というのが囚人氏の主張と見受けましたが。

論点は二つで、

1.シンプルなスコープでアンマネージリソースを用いる場合はusingで片付くが、
スコープが単純に定義できない寿命の長いケースにおいて、
プログラマが間違えようのないEoDな方法論はあるか?

2.IDisposableなオブジェクトが内部にIDisposableを持っているような
多段のIDisposableにおいて正しい順序でcloseされることを強制できるか?

なのかなぁと思いましたが、いかがでしょうか。
複雑なスコープとなる場合、単一の所有者と借用者という考えは有用そうですね。
本来の所有者以外からのcloseを受け付けない仕組みとか作れないですかね。
所有者がcloseを宣言した後にまだ借用者が参照を持っているという
事態は回避可能なのでしょうか。
Javaの弱参照のような扱いにするわけにもいかないでしょうし…。

このネタだけで面白い議論が続きそうですね。
2007/02/06 13:13 | nagise

# re: 再び、Dispose していいのかどうか悩むべき。

>みんな難しく考えすぎなんじゃないかなー

難しく考えなすぎて、Dispose しないとか、あるいは何でも Dispose してしまう事態が起こっているんじゃあないでしょうか。
確かに、所有者を意識して単純に考えると自ずと答えは見えてきそうですね。

>言語での制約などでEoD的な方向に転べばいいな、というのが囚人氏の主張と見受けましたが。

はい、その通りですね。「転べばいいな」という表現は非常に良いですね。

>本来の所有者以外からのcloseを受け付けない仕組みとか作れないですかね。
>所有者がcloseを宣言した後にまだ借用者が参照を持っているという
>事態は回避可能なのでしょうか。
>Javaの弱参照のような扱いにするわけにもいかないでしょうし…。

面白そうですね!何かいい方法ないですかねぇ…。
2007/02/06 21:53 | 囚人

# re: 再び、Dispose していいのかどうか悩むべき。

>難しく考えなすぎて、Dispose しないとか、あるいは何でも Dispose してしまう事態が起こっているんじゃあないでしょうか。

現実はそんなもんなんですかねー?
ごく僅かな「規定」といくつかの「原則」に従うだけで、手ひどい間違いは避けられると思うんですが。。。

要は「そういうもの」としてパラダイムを受け入れてしまうことが肝心で、下手に、new/delete のモデルに重ね合わせて理解しようとしたり、「常に、完全に同じものである」と言い切れもしない Close() を Dispose() と同じものだと思い込もうとする変な努力が泥沼化を招いているだけな気がするんですよねー

そういう観点で言うと

>1.シンプルなスコープでアンマネージリソースを用いる場合はusingで片付くが、
>スコープが単純に定義できない寿命の長いケースにおいて、
>プログラマが間違えようのないEoDな方法論はあるか?

については、答えは「NO」です。

いくつかのグループに分類することは出来ると思いますが、最終的には「そのクラスの設計に即した適切な手順」でそのクラスを扱うべきです。(実に当たり前の話ですが)

>本来の所有者以外からのcloseを受け付けない仕組みとか作れないですかね。

「所有者」がずっと一人であるなら、RealProxy で包んでやれば何とかなるんじゃないですかね?

2007/02/06 23:02 | 渋木宏明(ひどり)

# re: 再び、Dispose していいのかどうか悩むべき。

>現実はそんなもんなんですかねー?

悲しいかな、そういう場面をいくつか見受けますね。

>ごく僅かな「規定」といくつかの「原則」に従うだけで、手ひどい間違いは避けられると思うんですが。。。

そういう「規定」と「原則」を、言語でかなり強制できるとか裏で自動でやってくれたらいいなぁという感じです。

>「所有者」がずっと一人であるなら、RealProxy で包んでやれば何とかなるんじゃないですかね?

ちょっとどんなイメージかわからなかったのですが、例えば参照カウンタ方式とかって事でしょうか?
2007/02/07 21:41 | 囚人

# re: 再び、Dispose していいのかどうか悩むべき。

>そういう「規定」と「原則」を、言語でかなり強制できるとか裏で自動でやってくれたらいいなぁという感じです。

そりゃそうでしょうが、現実にそうではないですよね?

なら、「あるがまま」を冷静に受け止めるしかないと思うんだけど、どーして自分なりの変形を加えたがるのでしょうか?>混乱している人々

改良案があるなら、MSDN フォーラムや Global サミット他で提案すればいいわけじゃないですか。

既にリリースされているバージョンに対してどうこう言っても、リリース済みのバージョンに対しては、そうそうドラスティックな変更はなされっこないわけだし。

>ちょっとどんなイメージかわからなかったのですが、例えば参照カウンタ方式とかって事でしょうか?

いいえ。

元オブジェクトを RealProxy で包んであげて、「借用者」からの IDisposable.Dispose() 呼び出しは RealProxy の段階で無視。

で、「借用者」がひとりもいなくなった時点で本来の「所有者」が正規の手順でオブジェクトインスタンスを解放、みたいなイメージです。
2007/02/09 21:30 | 渋木宏明(ひどり)

# re: 再び、Dispose していいのかどうか悩むべき。

>で、「借用者」がひとりもいなくなった時点で

という部分をカウントしていけないとだめなんじゃないかな、と思ったのですが。RealProxy をあまりよく理解していないので何とも言えませんけども。

>なら、「あるがまま」を冷静に受け止めるしかないと思うんだけど、どーして自分なりの変形を加えたがるのでしょうか?>混乱している人々

あるがままを受け入れなければならないのは全くその通りですね。ただ、自分で IDisposable を実装するクラスを作るときはちょっと工夫してみては?という感じです。
2007/02/10 23:00 | 囚人

# re: 再び、Dispose していいのかどうか悩むべき。

>>で、「借用者」がひとりもいなくなった時点で
>
>という部分をカウントしていけないとだめなんじゃないかな、と思ったのですが。

あーなるほど。DI コンテナのようなものを想定してたんで、要らないよなーと思ってました。
汎用的なものを作ろうとすると必要かもしれませんね。

>自分で IDisposable を実装するクラスを作るときはちょっと工夫してみては?

については、ヘルプで Disposable パターンが提案されています。
が、さらに追補となる情報があってもよいですね。

個人的には

・IDisposable.Dispose() は明示的実装とし、public メソッドにはしない
・「Close() が IDisposable.Dispose() のエイリアスである」ような説明は誤解の元なので止める
・Close(), Disconnect() 等、正常系で「使用終了」をオブジェクトインスタンスに通知するメソッドを実装する
・IDisposable.Dispose() は何度呼び出してもよいこととする
・IDisposable.Dispose() は例外を throw しないこと(推奨?)

辺りは「原則」に追加したいところです。
2007/02/11 14:17 | 渋木宏明(ひどり)

# re: 再び、Dispose していいのかどうか悩むべき。

>については、ヘルプで Disposable パターンが提案されています。
>が、さらに追補となる情報があってもよいですね。

それは良いですね。
特に「IDisposable.Dispose() は明示的実装とし、public メソッドにはしない 」
なんかは守られると大きく違いますね。
2007/02/11 16:12 | 囚人

# re: 再び、Dispose していいのかどうか悩むべき。

>なんかは守られると大きく違いますね。

なんですが、Bitmap 他の GDI+ 系のクラスは Dispose() メソッドを公開しています。

でもこれは、IDisposable.Dispose() を公開しているのではなく、Close() や Disconnect() と同等の意味で Dispose() を公開している、と見ることも出来ます。(でないとイロイロ台無し)

2007/02/14 8:49 | 渋木宏明(ひどり)

# 【短期集中連載】IDisposable:第一回「前提編」

【短期集中連載】IDisposable:第一回「前提編」
2007/03/27 15:45 | .COM -どっとこむ-

# I'm no longer sure where you're getting your info, however great topic. I needs to spend some time studying much more or working out more. Thanks for magnificent information I used to be in search of this info for my mission.

I'm no longer sure where you're getting your info, however great topic.
I needs to spend some time studying much more or working out more.
Thanks for magnificent information I used to be in search of this info for my mission.

コメントの投稿

タイトル
名前
URL
コメント