1

In particular, I'm thinking of a scenario like this:

    unsafe struct Foo
    {
        public int Bar;

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

Assuming a Foo stored in unmanaged memory, I'm trying to figure out what is involved in evaluating the fixed statement in GetMyAddr. I know as the programmer that this struct is never on the managed heap, I just need to get it's address in unmanaged memory in the most efficient manner. I'm especially concerned if there's any locking or atomic operations used here as that would make it completely unsuitable.

Eloff
  • 20,828
  • 17
  • 83
  • 112
  • If you've allocated the Foo in unmanaged memory, then you should already have a Foo* and should use that for all of your Foo operations. – Dan Bryant Jul 23 '10 at 23:53
  • Sure I have a Foo*, but sadly the struct Foo does not. Most of the time "this" suffices, but I've encountered several scenarios where I need the address of Foo in a method of Foo. – Eloff Jul 24 '10 at 17:34

4 Answers4

7

This won't do what you think it will do. The "fixed" statement only pins the managed object (this) for the duration of the "fixed" statement itself, which ends as soon as you "return". See the MSDN docs for the details.

You already say your "Foo" is in unmanaged memory, which means that the managed GC isn't going to be moving it around on you. In that case, can't you just return "&this" directly? Alternatively, you may want to consider taking your unmanaged object and marshalling it into a managed one. Give a little more context around what you're doing and we'll all be able to give more specific advice.

JaredReisinger
  • 6,955
  • 1
  • 22
  • 21
  • 3
    Yep. He'd need a GCHandle to hold it fixed for any duration outside of that. – Steven Sudit Jul 23 '10 at 23:30
  • Yes, I know the pinning ends when it returns, but the fixed statement here is a noop, all it does it make &this compile, and at runtime I imagine it checks to see if this is on the managed heap (which it is not) and then just returns &this. – Eloff Jul 24 '10 at 17:31
2

The expression &this has no meaning when the structure is present in unmanaged memory. There is no way to allocate it there. A key property of managed structures is that their memory layout is not discoverable and is not compatible with the unmanaged view of that structure. The CLR rearranges fields as it sees fit to get the minimum size while aligning members. It will in fact swap fields if a later one can fit in the padding.

You cannot get past Marshal.PtrToStructure to convert an unmanaged struct to its managed version. Marshal.SizeOf is only accurate for the unmanaged layout.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Not true at all, using the struct layout attributes you can have fine control over the layout of the fields in the struct, you can even create something very close to a union in C# like this. – Eloff Jul 24 '10 at 17:36
  • @Eloff: you'll need to show a [StructLayout] that reliably swaps fields like the CLR does. Reference: http://stackoverflow.com/questions/1918037/layout-of-net-value-type-in-memory – Hans Passant Jul 24 '10 at 17:56
  • I see, I wasn't aware that the CLR could ignore LayoutSequential, makes it kind of pointless. But for putting a struct in unmanaged memory from C#, and using it in C#, it shouldn't matter, the CLR knows how it is laying everything out. – Eloff Jul 24 '10 at 20:00
0

Basically there's no overhead at all. Fixed means "pin the location the pointer points to in memory, don't relocate it." Every other managed pointer can be "bent" by the Garbage Collector at will if it decides to move memory around. Fixed will prevent this, so basically it will "save" this (possible) overhead.

I don't know about the implementation of fixed pointers, but in the simplest case it's just blacklisting memory blocks. This is not very costly compared to normal managed pointers.

On the other hand, it prevents all sorts of optimazations that the GC might decide to perform in terms of memory management like increasing localization, reducing fragmenation etc.

Johannes Rudolph
  • 35,298
  • 14
  • 114
  • 172
  • 1
    Downvoted due to the statement that "there's no overhead at all" followed by "I don't know about the implementation of fixed pointers". – Martin Törnwall Oct 26 '17 at 08:04
0

I set up a micro benchmark and measured the overhead of fixed when used on a struct in unmanaged memory, it is very low, returning fixed(this) is only 10 times more expensive than simply returning this. That's acceptable for my use case (hashing using the address of the struct.) I was unable to learn how it was implemented, but it does seem to be fast enough in this case.

Eloff
  • 20,828
  • 17
  • 83
  • 112