2

我有一个类(参见下面的示例),它充当 CUDA 内存结构的 .NET 包装器,
使用 cudaMalloc() 分配并使用 IntPtr 类型的成员字段引用。
(该类使用包含各种 CUDA 功能的本机 C DLL 的 DllImport。)

dispose 方法检查指针是否为 IntPtr.Zero,如果不是,则调用 cudaFree()
成功释放内存(返回 CUDA 成功)
并将指针设置为IntPtr. 零。

finalize 方法调用 dispose 方法。

问题是,如果调用 finalize 方法而之前没有调用 dispose,
则 cudaFree() 函数会设置“无效设备指针”的错误代码。

我检查了一下,cudaFree() 接收到的地址与 cudaMalloc() 返回的地址相同,并且之前没有调用 dispose()。

当我添加对 dispose() 的显式调用时,相同的地址被成功释放。

我发现的唯一解决方法是不要从终结器调用 dispose 方法,但是,如果并不总是调用 dispose(),这可能会导致内存泄漏。

任何想法为什么会发生这种情况?- 我在 .NET 3.5 SP1 上的 Windows Vista 64 位 + GeForce 8800 和 Windows XP 32 位 + Quadro FX 上遇到了与 CUDA 2.2 和 2.3 相同的问题(不确定哪个数字)。

类 CudaEntity : IDisposable
{
    私有 IntPtr 数据指针;

    公共 CudaEntity()
    {
        // 通过 DllImport 调用 cudaMalloc(),
        // 接收错误码,如果不为 0 则抛出期望
        // 给 this.dataPointer 赋值
    }

    公共处置()
    {
        if (this.dataPointer != IntPtr.Zero)
        {
            // 通过 DllImport 调用 cudaFree(),
            // 接收错误码,如果不为 0 则抛出期望

            this.dataPointer = IntPtr.Zero;
        }
    }

    ~CudaEntity()
    {
        处置();
    }
}
{
    //这段代码有效
    var myEntity = new CudaEntity();
    myEntity.Dispose();
}
{
    // 此代码导致“无效的设备指针”
    // 终结器调用 cudaFree() 时出错
    var myEntity = new CudaEntity();
}
4

1 回答 1

3

问题是终结器是在 GC 线程上执行的,在一个线程中分配的 CUDA 资源不能在另一个线程中使用。来自 CUDA 编程指南的片段:

多个主机线程可以在同一设备上执行设备代码,但根据设计,主机线程只能在一个设备上执行设备代码。因此,需要多个主机线程来在多个设备上执行设备代码。此外,在一个主机线程中通过运行时创建的任何 CUDA 资源都不能被另一个主机线程的运行时使用。

最好的办法是使用该using语句,它确保Dispose()始终在“受保护”代码块的末尾调用该方法:

using(CudaEntity ent = new CudaEntity())
{

}
于 2009-09-19T23:52:04.970 回答