C# 在非托管结构上使用fixed语句的开销是多少?

C# 在非托管结构上使用fixed语句的开销是多少?,c#,unsafe,C#,Unsafe,特别是,我想到这样一个场景: unsafe struct Foo { public int Bar; public Foo* GetMyAddr() { fixed (Foo* addr = &this) return addr; } } 假设一个Foo存储在非托管内存中,我将试图找出在GetMyAddr中计算fixed语句所涉及的内容。作为

特别是,我想到这样一个场景:

    unsafe struct Foo
    {
        public int Bar;

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

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

基本上没有任何开销。固定意味着在内存中锁定指针指向的位置,不要重新定位它。如果垃圾收集器决定四处移动内存,则它可以随意弯曲其他所有托管指针。修复将防止这种情况,因此基本上它将节省这种可能的开销

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


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

基本上没有任何开销。固定意味着在内存中锁定指针指向的位置,不要重新定位它。如果垃圾收集器决定四处移动内存,则它可以随意弯曲其他所有托管指针。修复将防止这种情况,因此基本上它将节省这种可能的开销

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


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

这不会像您认为的那样。fixed语句仅在fixed语句本身的持续时间内固定托管对象,该持续时间在您返回时立即结束。有关详细信息,请参阅


您已经说过您的Foo位于非托管内存中,这意味着托管GC不会在您身上移动它。那样的话,你就不能直接返回这个吗?或者,您可能想考虑接管非托管对象并将其编组为托管对象。在你所做的事情上多提供一些背景知识,我们都能给出更具体的建议。

这不会做你认为它会做的事情。fixed语句仅在fixed语句本身的持续时间内固定托管对象,该持续时间在您返回时立即结束。有关详细信息,请参阅


您已经说过您的Foo位于非托管内存中,这意味着托管GC不会在您身上移动它。那样的话,你就不能直接返回这个吗?或者,您可能想考虑接管非托管对象并将其编组为托管对象。在你所做的事情周围多提供一些上下文,我们都能给出更具体的建议。

当结构存在于非托管内存中时,这个表达式没有任何意义。没有办法在那里分配。托管结构的一个关键属性是它们的内存布局不可发现,并且与该结构的非托管视图不兼容。CLR根据需要重新排列字段,以在对齐成员时获得最小大小。事实上,如果后面的字段可以放入填充中,它将交换字段


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

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


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

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

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

是的。他需要一个GCHandle来保持它在除此之外的任何时间内都是固定的。是的,我知道当它返回时,固定语句就结束了,但是这里的fixed语句是一个noop,它所做的一切&这个编译,并且在运行时我想象它会检查它是否在托管堆上,然后只返回&this.Yep。他需要一个GCHandle来保持它在这段时间之外的固定状态。是的,我知道钉住在它返回时结束,但这里的固定语句是一个noop,它所做的一切&编译,在运行时,我想象它会检查这是否在托管堆上,而不是,然后返回&this。如果您在非托管内存中分配了Foo,那么您应该已经有一个Foo*,并且应该在所有Foo操作中使用它。当然我有一个Foo*,但遗憾的是结构Foo没有。大多数情况下,这就足够了,但我遇到过几种情况,其中我需要Foo方法中的Foo地址。如果您在非托管内存中分配了Foo,那么您应该已经有一个Foo*,并且应该将其用于所有Foo操作。当然我有一个Foo*,但遗憾的是结构Foo没有。大多数情况下,这就足够了,但我遇到过几种情况,其中我需要Foo方法中的Foo地址。完全不是这样,使用struct layout属性可以很好地控制struct中字段的布局,甚至可以在C中创建类似于这样的并集。@Eloff:您需要显示一个[结构布局]这就像CLR一样可靠地交换字段。参考:我明白了,我不知道CLR可以忽略LayoutSequential,这使它变得毫无意义。但是对于从C将结构放在非托管内存中,并在C中使用它,这不重要,CLR知道它是如何布置所有内容的。如果使用C中的struct layout属性,则一点也不正确如果您能够很好地控制结构中字段的布局,您甚至可以在C中创建类似于并集的内容。@Eloff:您需要显示[StructLayout]这就像CLR一样可靠地交换字段。引用:我知道,我不知道CLR可以忽略LayoutSequential,这使得它有点毫无意义。但是对于从C将结构放入非托管内存,并在C中使用它,这不重要,CLR知道它是如何布置所有内容的。由于声明没有开销,所以被否决我不知道固定指针的实现。由于声明根本没有开销,我投了反对票。我不知道固定指针的实现。