您好我有一个非托管函数,它接受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);
}
答案 0 :(得分:2)
我的MC ++有点生疏,但我认为__pin会固定源变量,直到“pinned_data”超出范围(至少,这就是C ++ / CLI中等效的pin_ptr所做的)。你通常应该尽快解锁它,即出于性能原因你不应该在相同的范围内调用fx。
在这种情况下是否需要钉扎?
是。您希望从非托管代码访问托管内存。
gc可以在memcpy
之前解除分配
没有。有强烈的数据引用,因此gc不会收集它。然而,它可能会收集一些其他对象,并在压缩步骤中将数据移动到内存中。然后malloc将访问错误的内存区域。固定可以防止这种情况,但代价是GC的额外簿记(这就是为什么你应该尽快解除对象的原因)。
malloc是否会分配非托管内存,即使它在托管代码中使用?
是
答案 1 :(得分:0)
你需要测试它实际上已分配指针的malloc。 不知道C ++ / CLI所以我不知道你的引脚是否可行。您是否需要使用编组库来保证在复制内存时固定内存?
答案 2 :(得分:0)
答案 3 :(得分:0)
你是
假设数据数组的大小至少相同。这是一个等待发生的错误
不检查malloc()
无论如何你可能不需要这样做,简单地传递固定字节指针应该没问题(除非被调用的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启动移动引用),存在固定指针以使这安全且简单,因为它既需要一个指针,并且在该指针的生命周期内阻止运行时将指向变量移动
答案 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);
}
不过,我还有几个问题: