1

特别是,我正在考虑这样的场景:

    unsafe struct Foo
    {
        public int Bar;

        public Foo* GetMyAddr()
        {
            fixed (Foo* addr = &this)
                return addr;
        }
    }

假设 Foo 存储在非托管内存中,我试图弄清楚在评估 GetMyAddr 中的固定语句所涉及的内容。作为程序员,我知道这个结构永远不在托管堆上,我只需要以最有效的方式在非托管内存中获取它的地址。我特别担心这里是否使用了任何锁定或原子操作,因为这会使其完全不合适。

4

4 回答 4

7

这不会做你认为它会做的事情。“固定”语句仅在“固定”语句本身的持续时间内固定托管对象(this),一旦您“返回”,该语句就会结束。有关详细信息,请参阅MSDN 文档

您已经说过您的“Foo”在非托管内存中,这意味着托管 GC 不会在您身上移动它。那样的话,就不能直接返回“&this”吗?或者,您可能需要考虑采用非托管对象并将其编组为托管对象。提供更多有关您正在做的事情的背景信息,我们都将能够提供更具体的建议。

于 2010-07-23T23:28:14.080 回答
2

当结构存在于非托管内存中时,表达式 &this 没有任何意义。没有办法在那里分配它。托管结构的一个关键特性是它们的内存布局是不可发现的,并且与该结构的非托管视图兼容。CLR 在它认为合适的时候重新排列字段,以便在对齐成员时获得最小大小。如果后面的字段适合填充,它实际上会交换字段。

您无法通过 Marshal.PtrToStructure 将非托管结构转换为其托管版本。Marshal.SizeOf 仅适用于非托管布局。

于 2010-07-23T23:46:07.947 回答
0

基本上没有任何开销。固定意味着“将指针指向的位置固定在内存中,不要重新定位它。” 如果垃圾收集器决定移动内存,则每个其他托管指针都可以随意“弯曲”。固定将防止这种情况发生,因此基本上它将“保存”这个(可能的)开销。

我不知道固定指针的实现,但在最简单的情况下,它只是将内存块列入黑名单。与普通托管指针相比,这并不是很昂贵。

另一方面,它阻止了 GC 可能决定在内存管理方面执行的各种优化,例如增加本地化、减少碎片等。

于 2010-07-23T23:25:08.413 回答
0

我设置了一个微基准测试并测量了在非托管内存中的结构上使用时固定的开销,它非常低,返回固定(this)仅比简单地返回 this 贵 10 倍。这对于我的用例是可以接受的(使用结构的地址进行散列)。我无法了解它是如何实现的,但在这种情况下它似乎确实足够快。

于 2010-07-28T16:34:54.743 回答