Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

152
Views
Alineación de estructuras dentro de una clase en .NET Core

Estoy tratando de entender por qué una estructura que contiene solo int toma 8 bytes de memoria dentro de una clase.

considerando el siguiente código;

 static void Main() { var rand = new Random(); var twoIntStruct = new TwoStruct(new IntStruct(rand.Next()), new IntStruct(rand.Next())); var twoInt = new TwoInt(rand.Next(), rand.Next()); Console.ReadLine(); } public readonly struct IntStruct { public int Value { get; } internal IntStruct(int value) { Value = value; } } public class TwoStruct { private readonly IntStruct A; private readonly IntStruct B; public TwoStruct( IntStruct a, IntStruct b) { A = a; B = b; } } public class TwoInt { private readonly int A; private readonly int B; public TwoInt( int a, int b) { A = a; B = b; } }

ahora, cuando perfilo estas dos instancias con dotMemory, obtengo el siguiente resultado:

ingrese la descripción de la imagen aquí

Aunque tanto int como intStruct ocupan 4 bytes de memoria en la pila, parece que el tamaño de la clase en el montón es diferente y esa estructura siempre está alineada con 8 bytes.

¿Qué puede causar este comportamiento?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Para las clases, el diseño de memoria predeterminado es "Auto", lo que significa que CLR decide cómo alinear los campos en una clase en la memoria. Es un detalle de implementación no documentado. Por algún motivo que desconozco, alinea los campos de los tipos de valores personalizados en un límite de tamaño de puntero (es decir, 8 bytes en un proceso de 64 bits, 4 bytes en un proceso de 32 bits).

Si compila ese código en 32 bits, verá que tanto TwoInt como TwoStruct ahora toman 16 bytes (4 para el encabezado del objeto, 4 para el puntero de la tabla de métodos y luego 8 para los campos), porque ahora están alineados en 4 bytes. Perímetro.

En el caso de 64 bits, como en su pregunta, los tipos de valores personalizados están alineados en un límite de 8 bytes, por lo que TwoStruct tiene un diseño de:

 Object Header (8 bytes) Method Table Pointer (8 bytes) IntStruct A (4 bytes) padding (4 bytes, to align at 8 bytes) IntStruct B (4 bytes) padding (4 bytes)

Y TwoInt es solo

 Object Header (8 bytes) Method Table Pointer (8 bytes) IntStruct A (4 bytes) IntStruct B (4 bytes)

Debido a que int no es un tipo de valor personalizado, CLR no lo alinea en el límite del tamaño del puntero. Si en lugar de IntStruct LongStruct y long en lugar de int , entonces ambos casos tendrían el mismo tamaño, porque long es de 8 bytes e incluso para la estructura personalizada, CLR no necesitará agregar ningún relleno para alinearlo en el límite de 8 bytes en 64 -poco.

Aquí hay un artículo interesante relacionado con el tema. El autor desarrolla una herramienta bastante interesante para inspeccionar el diseño de la memoria de los objetos directamente desde el código .NET (sin herramientas externas). Él investiga este mismo problema y llega a la conclusión anterior:

Si el diseño de tipo es LayoutKind.Auto, CLR rellenará cada campo de un tipo de valor personalizado. Esto significa que si tiene varias estructuras que envuelven solo un int o byte y se usan ampliamente en millones de objetos, ¡podría tener una sobrecarga de memoria notable debido al relleno!

Puede afectar el diseño administrado de una clase con StructLayouAttribute con LayoutKind = Sequential SI todos los campos en esta clase son blittables (que es el caso en esta pregunta):

Para los tipos blittables, LayoutKind.Sequential controla tanto el diseño en la memoria administrada como el diseño en la memoria no administrada. Para los tipos que no se pueden dividir, controla el diseño cuando la clase o la estructura se calculan en código no administrado, pero no controla el diseño en la memoria administrada.

Entonces, como se menciona en los comentarios, podemos eliminar el relleno haciendo:

 [StructLayoutAttribute(LayoutKind.Sequential, Pack = 4)] public class TwoStruct { private readonly IntStruct A; private readonly IntStruct B; public TwoStruct( IntStruct a, IntStruct b) { A = a; B = b; } }

Lo que en realidad nos ahorrará algo de memoria.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!