是否可以在没有 pin_ptr 的情况下将托管字节数组转换为本机结构,以免对 GC 造成太多干扰?

Is it possible to cast a managed bytes-array to native struct without pin_ptr, so not to bug the GC too much?

仅使用 pin_ptr 就可以将托管 array<Byte>^ 转换为某些非托管 struct,据我所知,例如:

void Example(array<Byte>^ bfr) {
    pin_ptr<Byte> ptr = &bfr[0];
    auto data = reinterpret_cast<NonManagedStruct*>(ptr);
    data->Header = 7;
    data->Length = sizeof(data);
    data->CRC = CalculateCRC(data);
}

不过,跟interior_ptr有什么关系吗?

我宁愿以低级方式处理托管数据(使用 unions、struct 位字段等),而不固定数据 - 我可以持有此数据相当长一段时间,不想骚扰 GC.

澄清:

我不想将托管数据复制到本机并返回(因此 Marshaling 方式在这里不是一个选项...)

您可能不会用 pin_ptr 骚扰 GC - 与 GCHandle 不同,它非常轻巧。

GCHandle::Alloc(someObject, GCHandleType::Pinned) 实际上会将对象注册为固定在 GC 中。这使您可以在更长的时间段内固定对象并跨函数调用,但 GC 必须跟踪该对象。

另一方面,pin_ptr 被翻译成 IL 代码中的固定本地。 GC 不会收到有关它的通知,但它会看到该对象在收集期间仅 固定。也就是说,它会在堆栈上查找对象引用时注意到它的固定状态。


如果您真的想要,您可以通过以下方式访问堆栈内存:

[StructLayout(LayoutKind::Explicit, Size = 256)]
public value struct ManagedStruct
{
};

struct NativeStruct
{
    char data[256];
};

static void DoSomething()
{
    ManagedStruct managed;
    auto nativePtr = reinterpret_cast<NativeStruct*>(&managed);
    nativePtr->data[42] = 42;
}

这里根本没有固定,但这只是因为托管结构存储在堆栈中,因此首先不可重定位

这是一个复杂的例子,因为你可以这样写:

static void DoSomething()
{
    NativeStruct native;
    native.data[42] = 42;
}

...编译器会在幕后为您执行类似的技巧。