Memory alignment of classes in c#?

后端 未结 6 791
不思量自难忘°
不思量自难忘° 2020-12-17 15:35

(btw. This refers to 32 bit OS)

SOME UPDATES:

  • This is definitely an alignment issue

  • Sometimes the alignment (for whatever reason?) i

相关标签:
6条回答
  • 2020-12-17 15:59

    To prove the concept of misalignment of objects on heap in .NET you can run following code and you'll see that now it always runs fast. Please don't shoot me, it's just a PoC, but if you are really concerned about performance you might consider using it ;)

    public static class AlignedNew
    {
        public static T New<T>() where T : new()
        {
            LinkedList<T> candidates = new LinkedList<T>();
            IntPtr pointer = IntPtr.Zero;
            bool continue_ = true;
    
            int size = Marshal.SizeOf(typeof(T)) % 8;
    
            while( continue_ )
            {
                if (size == 0)
                {
                    object gap = new object();
                }
    
                candidates.AddLast(new T());
    
                GCHandle handle = GCHandle.Alloc(candidates.Last.Value, GCHandleType.Pinned);
                pointer = handle.AddrOfPinnedObject();
                continue_ = (pointer.ToInt64() % 8) != 0 || (pointer.ToInt64() % 64) == 24;
    
                handle.Free();
    
                if (!continue_)
                    return candidates.Last.Value;
            }
    
            return default(T);
        }
    }
    
    class Program
    {
    
        [StructLayoutAttribute(LayoutKind.Sequential)]
        public class Variable
        {
            public double Value;
        }
    
        static void Main()
        {
    
            const int COUNT = 10000000;
    
            while (true)
            {
    
                var x = AlignedNew.New<Variable>();
    
    
                for (int inner = 0; inner < 5; ++inner)
                {
    
                    var stopwatch = Stopwatch.StartNew();
    
                    var total = 0.0;
                    for (int i = 1; i <= COUNT; ++i)
                    {
                        x.Value = i;
                        total += x.Value;
                    }
                    if (Math.Abs(total - 50000005000000.0) > 1)
                        throw new ApplicationException(total.ToString());
    
    
                    Console.Write("{0}, ", stopwatch.ElapsedMilliseconds);
                }
                Console.WriteLine();
            }
    
        }
    }
    
    0 讨论(0)
  • 2020-12-17 16:00

    Maybe the StructLayoutAttribute is what you are looking for?

    0 讨论(0)
  • It will be correctly aligned, otherwise you'd get alignment exceptions on x64. I don't know what your snippet shows, but I wouldn't say anything about alignment from it.

    0 讨论(0)
  • 2020-12-17 16:14

    Interesting look in the gears that run the machine. I have a bit of a problem explaining why there are multiple distinct values (I got 4) when a double can be aligned only two ways. I think alignment to the CPU cache line plays a role as well, although that only adds up to 3 possible timings.

    Well, nothing you can do about it, the CLR only promises alignment for 4 byte values so that atomic updates on 32-bit machines are guaranteed. This is not just an issue with managed code, C/C++ has this problem too. Looks like the chip makers need to solve this one.

    If it is critical then you could allocate unmanaged memory with Marshal.AllocCoTaskMem() and use an unsafe pointer that you can align just right. Same kind of thing you'd have to do if you allocate memory for code that uses SIMD instructions, they require a 16 byte alignment. Consider it a desperation-move though.

    0 讨论(0)
  • 2020-12-17 16:14

    Using struct instead of class, makes the time constant. also consider using StructLayoutAttribute. It helps to specify exact memory layout of a structures. For CLASSES I do not think you have any guarantees how they are layouted in memory.

    0 讨论(0)
  • 2020-12-17 16:15

    You don't have any control over how .NET lays out your class in memory.

    As others have said the StructLayoutAttribute can be used to force a specific memory layout for a struct BUT note that the purpose of this is for C/C++ interop, not for trying to fine-tune the performance of your .NET app.

    If you're worried about memory alignment issues then C# is probably the wrong choice of language.


    EDIT - Broke out WinDbg and looked at the heap running the code above on 32-bit Vista and .NET 2.0.

    Note: I don't get the variation in timings shown above.

    0:003> !dumpheap -type Sample+Variable
     Address       MT     Size
    01dc2fec 003f3c48       16     
    01dc54a4 003f3c48       16     
    01dc58b0 003f3c48       16     
    01dc5cbc 003f3c48       16     
    01dc60c8 003f3c48       16     
    01dc64d4 003f3c48       16     
    01dc68e0 003f3c48       16     
    01dc6cd8 003f3c48       16     
    01dc70e4 003f3c48       16     
    01dc74f0 003f3c48       16     
    01dc78e4 003f3c48       16     
    01dc7cf0 003f3c48       16     
    01dc80fc 003f3c48       16     
    01dc8508 003f3c48       16     
    01dc8914 003f3c48       16     
    01dc8d20 003f3c48       16     
    01dc912c 003f3c48       16     
    01dc9538 003f3c48       16     
    total 18 objects
    Statistics:
          MT    Count    TotalSize Class Name
    003f3c48       18          288 TestConsoleApplication.Sample+Variable
    Total 18 objects
    0:003> !do 01dc9538 
    Name: TestConsoleApplication.Sample+Variable
    MethodTable: 003f3c48
    EEClass: 003f15d0
    Size: 16(0x10) bytes
     (D:\testcode\TestConsoleApplication\bin\Debug\TestConsoleApplication.exe)
    Fields:
          MT    Field   Offset                 Type VT     Attr    Value Name
    6f5746e4  4000001        4        System.Double  1 instance 1655149.000000 Value
    

    This seems to me that the classes' allocation addresses appear to be aligned unless I'm reading this wrong?

    0 讨论(0)
提交回复
热议问题