C++の遺産をC#で使う為に、C++/CLIでラッピングなんてしているわけですが。
ものにも依りますが、おおむね
Vista到来。既存C/C++資産の.NET化を始めよう!
[http://www.atmarkit.co.jp/fdotnet/special/vcppinvista01/vcppinvista01_02.html]に書いてあるように、
コンストラクタ、デストラクタ、ファイナライザと、メンバ変数としてネイティブクラスへのポインタ、
くらいを持っておけば何とかなるなる。
ただ、
ネイティブ側のクラスが、ばかでかいメモリをヒープに確保するようなものだと、
なんかメモリ不足になることがあった。
例えば、自前でBitmap画像のバイト配列を用意して管理するようなネイティブのクラスを考える。
当然、ネイティブでこのクラスを使う場合には、
newとdeleteは意識して行うか、あるいはstd::auto_ptrとかboost::shared_ptrなんかを使うので、
寿命が明確に定まる。
ので、メモリ不足になるのはそりゃプログラマが悪いぞと。
しかし、これをマネージドに持って行くと話は別で、
なんかマネージドのものだと、勝手にGCが破棄してくれるから、とりあえず作っちゃえ、みたいになるわけです。
.NETにゃdeleteないじゃん。
いや、Dispose使えとかusingに入れろとか言われると耳が痛いのですが、
だってあなた.NETじゃないですか。GCに任せたくなるじゃないですか。
DisposeはGCに任せてはいけないとかいう話は、んまぁ聞いたことはありますが、
んまぁ、上の記事だとデストラクタはファイナライザを呼んでるわけだし。
マネージドでくるんだクラスをnewしては放置、newしては放置してると、
どんどん使用メモリが増えていって、
あるとき突然GCが働いてちゅどーんとメモリが減る。
ところがさ、ときどきこれが失敗するのよねん。
マネージドでくるんだ側のクラスをnew(gcnew)すると、マネージドのコンストラクタが働く。
このコンストラクタで、内部に持ってるネイティブクラスを(ネイティブのヒープに)newする。
このnewが失敗して、std::bad_allocを返す。
そして、これを捕ったCLR(?)がなんとか(名前忘れた。Win32なんとかかんとか)っていう例外を返す。
というような怪奇現象が何度も現れた。
GCの発動が遅すぎて、ネイティブのnewが先走っちゃったと解釈すればよろしいのでしょうか。
定期的に(メモリがあふれる前に)、
System.GC.Collect()
で強制的に手動でGCを発動してあげると、んまぁ、なんか根本的な解決にはなってないけど何とかなった。
そんなこともあるってことで。
全部マネージドの世界に閉じこもってしまえれば楽なのかもしれない。
PR