読者です 読者をやめる 読者になる 読者になる

アンマネージ関数にdelegateを渡すと落ちるのは解決

delegateとかアンマネージとかあまり関係有りませんでした、すみません。Releaseモードだとオブジェクトの生存期間が変わってしまうのが原因でした。基本的には以下のページと同様の現象です。

http://blogs.wankuma.com/shuujin/archive/2007/05/15/76794.aspx

コード例を出すときにばっさり省いた箇所が原因でした。具体的にはCvMemStorage。

CvSeqをつくるには、配列データの格納先であるCvMemStorageが必要です。大抵深く考えずその場で作って渡してしまいますが、これが落とし穴。つまりこんなコードだったということです(delegate周りは大幅に省略)。

class Program
{
    CvSeq<int> seq;

    Program()
    {
        CvMemStorage storage = new CvMemStorage();
        seq = new CvSeq<int>(SeqType.EltypeS32C1, CvSeq.SizeOf, storage);

        for(int i=0; i<10000; i++)
        {
            Hoge();
        }
    }

    void Hoge()
    {
        seq.Push(0);
        GC.Collect();
    }

    static void Main(string[] args)
    {
        new Program();
    }
}

この様に、CvSeqだけフィールド変数にして安心していたら、そもそもの配列データが入っているCvMemStorageの方はGCで回収されてしまって、そのあとCvSeqを使おうとすると死亡、という流れのようです。
(ただしこの例のコードでは落ちないかもしれません。どうもうまく別のコードでは再現できない)

これの解決にはCvMemStorageもフィールドで定義するのが一番簡単ですが、なんだか今後もしょっちゅうはまりそうなので、CvSeqに渡されたCvMemStorageをCvSeq内部で保持しておくことにしました。これで上記のコードでも落ちなくなった、はず・・・

.NETのクラスライブラリ設計 開発チーム直伝の設計原則、コーディング標準、パターン (Microsoft.net Development Series)

.NETのクラスライブラリ設計 開発チーム直伝の設計原則、コーディング標準、パターン (Microsoft.net Development Series)