在托管的.NET代码中分配非托管内存

时间:2009-01-23 07:48:52

标签: .net arrays unmanaged managed

您好我有一个非托管函数,它接受malloc分配的一块内存,稍后以异步方式释放它。我想将它包装到托管包装器中。下面的代码好吗?

void managed_fx (byte data __gc[], size_t size)
{
    //  Pin the data
    byte __pin *pinned_data = &data [0];

    //  Copy data to the unmanaged buffer.
    void *unmanaged_data = malloc (size);
    memcpy (unmanaged_data, (byte*) pinned_data, size);

    //  Forward the call
    fx (unmanaged_data, size);
}

5 个答案:

答案 0 :(得分:2)

我的MC ++有点生疏,但我认为__pin会固定源变量,直到“pinned_data”超出范围(至少,这就是C ++ / CLI中等效的pin_ptr所做的)。你通常应该尽快解锁它,即出于性能原因你不应该在相同的范围内调用fx。

  

在这种情况下是否需要钉扎?

是。您希望从非托管代码访问托管内存。

  

gc可以在memcpy

之前解除分配

没有。有强烈的数据引用,因此gc不会收集它。然而,它可能会收集一些其他对象,并在压缩步骤中将数据移动到内存中。然后malloc将访问错误的内存区域。固定可以防止这种情况,但代价是GC的额外簿记(这就是为什么你应该尽快解除对象的原因)。

  

malloc是否会分配非托管内存,即使它在托管代码中使用?

答案 1 :(得分:0)

你需要测试它实际上已分配指针的malloc。 不知道C ++ / CLI所以我不知道你的引脚是否可行。您是否需要使用编组库来保证在复制内存时固定内存?

答案 2 :(得分:0)

阅读this,了解有关如何分配非托管数据的信息。看看Marshall课程。也许会有一些方法可以替换你的managed_fx函数。

答案 3 :(得分:0)

你是

  1. 假设数据数组的大小至少相同。这是一个等待发生的错误

  2. 不检查malloc()

  3. 的结果
  4. 无论如何你可能不需要这样做,简单地传递固定字节指针应该没问题(除非被调用的fx()函数以某种方式改变数据,在这种情况下复制可能是一个要求)。根据后来释放的内存,很可能这不可能。

  5. 考虑到这一点,这是一个固定的版本

    void managed_fx (byte data __gc[], size_t size)
    {
        if (data.Length < size)
            throw gcnew System.IndexOutOfRangeException(
                "the unmanaged buffer is not big enough");
        //  Pin the data
        byte __pin *pinned_data = &data [0];
    
        //  Copy data to the unmanaged buffer.
        void *unmanaged_data = malloc (size);
        if (unmanaged_data == NULL) 
            throw gcnew OutOfMemoryException(
                "could not allocate memory for the unmanaged buffer");
        memcpy (unmanaged_data, (byte*) pinned_data, size);
    
        //  Forward the call
        fx (unamanged_data, size);
    }
    

    回答进一步的问题:

    执行memcpy需要固定。它不会阻止GC运行时删除内存(技术上确实如此,但只是保持对它的引用)它会阻止它在内存中移动。由于memcpy是一个非托管函数 - 它无法处理它正在操作的指针在内存中移动。 malloc完全不受管理(尽管运行时库可以自由地使用托管堆的保留区域来执行此操作)。

    源C ++ / CLI中没有明确区分“代码”是管理还是非管理。在编译时,一些部分将是CIL中间代码,其他部分是普通本机代码,重要的是使用的变量是管理还是非管理。托管引用(具有^的任何内容)只能由本身管理的代码操作/使用。这意味着如果运行时改变了内存中托管对象的位置,那么运行时可以自由地改变它认为合适的底层指针的值。它以对托管函数安全的方式执行此操作(它们在围绕它们改变世界时暂停)。 由于存在许多有用的函数而不知道如何处理这样的托管引用,因此最终可能需要使用一个简单的指针。 由于此操作不安全(如果GC启动移动引用),存在固定指针以使这安全且简单,因为它既需要一个指针,并且在该指针的生命周期内阻止运行时将指向变量移动

答案 4 :(得分:0)

好的,让我们更简单:

void managed_fx (byte data __gc[])
{
     //  Pin the data
     byte __pin *pinned_data = &data [0];

     //  Copy data to the unmanaged buffer.
     void *unmanaged_data = malloc (data.Length);
     assert (unmanaged_data);
     memcpy (unmanaged_data, (byte*) pinned_data, data.Length);

     //  Forward the call
     fx (unamanged_data, data.Length);
 }

不过,我还有几个问题:

  1. 在这种情况下是否需要钉扎?在memcpy发生之前gc可以解除分配吗?
  2. malloc是否会分配非托管内存,即使它在托管代码中使用?