0

嗨,我有一个非托管函数,它占用 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);
}
4

5 回答 5

2

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

在这种情况下是否需要固定?

是的。您想从非托管代码访问托管内存。

gc 可以在 memcpy 之前释放它吗

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

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

是的。

于 2009-01-23T15:47:49.407 回答
0

你是

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

  2. 不检查 malloc() 的结果

  3. 无论如何,您可能不需要这样做,只需传递固定字节指针就可以了(除非调用的 fx() 函数以某种方式更改了数据,在这种情况下可能需要复制)。基于稍后释放的内存,这很可能是不可能的。

考虑到这一点,这里是一个固定版本

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 开始移动引用),存在固定指针以使其安全且易于执行,因为它既需要一个指针,并且该指针的生命周期会阻止运行时移动指向的变量.

于 2009-01-23T12:27:56.800 回答
0

你需要测试你的 malloc 它实际上已经分配了你的指针。不知道 C++/CLI,所以我不知道你的 pin 是否可以工作。您不需要使用 Marshalling 库来保证内存在复制时被固定吗?

于 2009-01-23T08:12:55.440 回答
0

阅读本文以获取有关如何分配非托管数据的信息。看看Marshall类。也许会有一些方法可以代替您的 managed_fx 功能。

于 2009-01-23T08:17:47.973 回答
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. 在这种情况下是否需要固定?gc 可以在 memcpy 发生之前释放它吗?
  2. malloc 是否分配非托管内存,即使它在托管代码中使用?
于 2009-01-23T15:32:14.603 回答