繁体   English   中英

了解C#中的GCHandle.Alloc固定

[英]Understanding GCHandle.Alloc pinning in C#

我无意间发现了一些对我来说毫无意义的东西。 我的问题在代码注释中和下面:

[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
[StructLayout(LayoutKind.Sequential, Size = 4096)]
public unsafe struct BufItems
{
    public fixed byte Buffer[4096];
}

public class Wrapper
{
    public BufItems Items;
    public int Id;
}

private unsafe void button10_Click(object sender, EventArgs e)
{
    Wrapper wrap = new Wrapper();
    wrap.Id = 123;

    fixed(BufItems* ptr = &wrap.Items)
    {
        ptr->Buffer[0] = 99;      // works fine
    }

    // fixed (Wrapper w = wrap)   { /* not possible */ };
    // fixed (Wrapper* w = &wrap) { /* not possible */ };

    // how come I can pin the object this way?
    GCHandle h = GCHandle.Alloc(wrap, GCHandleType.Pinned);

    // what exactly is p pointing to? Wrapper cannot have a pointer.
    IntPtr p = h.AddrOfPinnedObject();
}

我还有一个问题:我假设BufItems Items字段是作为一个对象创建的(因此是可固定的),而不是作为wrap类对象实例化的一部分,对吗? 否则,钉扎将无济于事,因为GC可能会移动wrap 但是,这是一个结构,在这种情况下,我认为结构已“嵌入”。 这里到底发生了什么?

让我们逐行解决您的问题:

fixed (Wrapper w = wrap)   { /* not possible */ };

fixed只允许声明一个指针变量。 但是请注意,可以对引用类型进行固定( fixed语句的作用),但没有那么有用,因此C#中没有使用它的方法。

fixed (Wrapper* w = &wrap) { /* not possible */ };

包装器是参考类型。 允许您获取指向包含对该变量引用的变量的指针,这又将使您能够访问该对象的实际地址,并使其陷入混乱。 您将能够将指针强制转换为object* ,然后将任何对象存储在变量中,从而打破类型安全性。

// how come I can pin the object this way?
GCHandle h = GCHandle.Alloc(wrap, GCHandleType.Pinned);

就像我已经说过的那样,实例固定可以在.NET中实现,但在语法上不能在C#中实现。 您可以使用此方法固定任何可出血类型(无参考字段)。 固定对象可确保其在堆上的位置不会改变。

// what exactly is p pointing to? Wrapper cannot have a pointer.
IntPtr p = h.AddrOfPinnedObject();

也许最好在此代码上进行说明:

int[] arr = new int[10];
fixed(int* p = arr) { ... }
fixed(int* p = &arr[0]) { ... }

这两行被编译为完全相同的CIL(为了提高性能),但是第一行也可以通过使用GCHandle的相同方法来实现。 AddrOfPinnedObject返回指向对象中第一个字段的指针,与fixed(BufItems* ptr = &wrap.Items)的指针相同。

BufItems是一种值类型,因此Items字段不包含引用,而是实际的固定数组及其后的int。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM