tags:

views:

70

answers:

4

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.

A: 

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
+6  A: 

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
Yep. He'd need a GCHandle to hold it fixed for any duration outside of that.
Steven Sudit
Eloff
+2  A: 

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
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
@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
@Hans: 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
A: 

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