垫子没有被正确销毁

Mat is not being destroyed properly

在我用 C# 编写的软件中,我实现了一个图像 class 供内部使用。在 class 里面,我拿着来自 emgu CV 的 Mat

class MyOwnImage : IDisposable
{
    private Mat mat;

    public MyOwnImage( Mat mat ) {
        this.mat = mat;
    }

    public void Dispose() {
        mat.Dispose();
    }
    //...
}

现在,我发现,无论我是否在 Image 对象上调用 Dispose(),我的内存使用量都在增长。我仔细查看了 Mat class 并发现它内部有未管理的内存,形式为 IntPtr。所以,我试了一下,如果手动释放指针会有所作为:

class MyOwnImage : IDisposable
{
    private Mat mat;

    public MyOwnImage( Mat mat ) {
        this.mat = mat;
    }

    public void Dispose() {
        Marshal.FreeHGlobal( mat.DataPointer ); // data pointer is the IntPtr
        mat.Dispose();
    }
    //...
}

有点意外,不过内存溢出的问题解决了。所以,我假设我必须手动销毁 Mat 对象中的数据。之后,我试图通过添加一个析构函数来使它更稳定,如果有人忘记手动 Dispose() 图像。

class MyOwnImage : IDisposable
{
    private Mat mat;

    public MyOwnImage( Mat mat ) {
        this.mat = mat;
    }

    ~MyOwnImage() {
        destroy();
    }

    private void destroy() {
        Marshal.FreeHGlobal( mat.DataPointer ); // data pointer is the IntPtr
        mat.Dispose();
    }

    public void Dispose() {
        destroy();
    }
    //...
}

可悲的是,这变成了一个新问题:有时,当调用析构函数时,Mat 对象似乎已经被销毁了。随后,在调用 FreeHGlobal(...) 的行上抛出一个 AccessViolationExcetion。现在,我做了另一个测试并删除了 Dispose() 函数中的 destroy() 调用。

class MyOwnImage : IDisposable
{
    private Mat mat;

    public MyOwnImage( Mat mat ) {
        this.mat = mat;
    }

    ~MyOwnImage() {
        destroy();
    }

    private void destroy() {
        Marshal.FreeHGlobal( mat.DataPointer ); // data pointer is the IntPtr
        mat.Dispose();
    }

    public void Dispose() {
        //destroy();
    }
    //...
}

奇怪的是,这并没有改变任何事实,当调用析构函数 ~MyOwnImage 时,MyOwnImage 中的 mat 似乎已经消失了。

最后,我想知道几件事:

  1. 有没有可能我手动调用Dispose()之后析构函数也会被调用?
  2. 是否有可能 MyOwnImage 的内部对象在调用此 class 的析构函数之前被销毁?
  3. 如果有OpenCV高手:有没有可能把垫子处理掉并没有释放里面的数据?如果是,这是错误还是有原因?

J...在评论中指出了这个问题

违反了所有权模式。正如他所建议的,我在 MyOwnImage 中克隆了 Mat 对象,现在它正在运行。

class MyOwnImage : IDisposable
{
    private Mat mat;

    public MyOwnImage( Mat passedMat ) {
        var copy = new Mat();
        passedMat.CopyTo( copy );
        mat = copy;
    }

    public void Dispose() {
        mat.Dispose();
    }
    //...
}