.net arrays overhead

Diseño de memoria de una matriz.NET



arrays overhead (4)

¿Cuál es el diseño de memoria de una matriz .NET?

Tomemos por ejemplo esta matriz:

Int32[] x = new Int32[10];

Entiendo que la mayor parte de la matriz es así:

0000111122223333444455556666777788889999

Donde cada carácter es un byte, y los dígitos corresponden a índices en el conjunto.

Además, sé que hay una referencia de tipo y un índice de sincronización de todos los objetos, por lo que lo anterior se puede ajustar a esto:

ttttssss0000111122223333444455556666777788889999 ^ +- object reference points here

Además, la longitud de la matriz debe ser almacenada, por lo que quizás esto sea más correcto:

ttttssssllll0000111122223333444455556666777788889999 ^ +- object reference points here

¿Está completo? ¿Hay más datos en una matriz?

La razón por la que estoy preguntando es que estamos tratando de estimar cuánta memoria tomarán un par de diferentes representaciones en memoria de un corpus de datos bastante grande y el tamaño de las matrices varía bastante, por lo que la sobrecarga podría tener una gran impacto en una solución, pero quizás no tanto en la otra.

Entonces, básicamente, para una matriz, la cantidad de sobrecarga que hay, esa es básicamente mi pregunta.

Y antes de que los arrays se activen bad squad, esta parte de la solución es una construcción estática, una vez de referencia, a menudo, por lo que no es necesario usar listas creíbles.


Gran pregunta Encontré este artículo que contiene diagramas de bloques para ambos tipos de valores y tipos de referencia. También vea este artículo en el que Ritcher afirma:

[snip] cada matriz tiene información de sobrecarga adicional asociada a ella. Esta información contiene el rango de la matriz (número de dimensiones), los límites inferiores para cada dimensión de la matriz (casi siempre 0) y la longitud de cada dimensión. La sobrecarga también contiene el tipo de cada elemento en la matriz.


Gran pregunta! Quería verlo por mí mismo, y me pareció una buena oportunidad para probar CorDbg.exe ...

Parece que para matrices de enteros simples, el formato es:

ssssllll000011112222....nnnn0000

donde s es el bloque de sincronización, l la longitud de la matriz y luego los elementos individuales. Parece que finalmente hay un 0 al final, no estoy seguro de por qué es así.

Para matrices multidimensionales:

ssssttttl1l1l2l2???????? 000011112222....nnnn000011112222....nnnn....000011112222....nnnn0000

donde s es el bloque de sincronización, t el número total de elementos, l1 la longitud de la primera dimensión, l2 la longitud de la segunda dimensión, luego dos ceros ?, seguidos por todos los elementos secuencialmente, y finalmente un cero nuevamente.

Las matrices de objetos se tratan como la matriz de enteros, los contenidos son referencias esta vez. Las matrices dentadas son matrices de objetos donde las referencias apuntan a otras matrices.


Un objeto de matriz tendría que almacenar cuántas dimensiones tiene y la longitud de cada dimensión. Por lo tanto, hay al menos un elemento de datos más para agregar a su modelo


Una forma de examinar esto es mirar el código en WinDbg. Entonces, dado el código a continuación, veamos cómo aparece eso en el montón.

var numbers = new Int32[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

Lo primero que debe hacer es localizar la instancia. Como hice esto local en Main() , es fácil encontrar la dirección de la instancia.

Desde la dirección podemos volcar la instancia real, lo que nos da:

0:000> !do 0x0141ffc0 Name: System.Int32[] MethodTable: 01309584 EEClass: 01309510 Size: 52(0x34) bytes Array: Rank 1, Number of elements 10, Type Int32 Element Type: System.Int32 Fields: None

Esto nos dice que es nuestra matriz Int32 con 10 elementos y un tamaño total de 52 bytes.

Vamos a volcar la memoria donde se encuentra la instancia.

0:000> d 0x0141ffc0 0141ffc0 [84 95 30 01 0a 00 00 00-00 00 00 00 01 00 00 00 ..0............. 0141ffd0 02 00 00 00 03 00 00 00-04 00 00 00 05 00 00 00 ................ 0141ffe0 06 00 00 00 07 00 00 00-08 00 00 00 09 00 00 00 ................ 0141fff0 00 00 00 00]a0 20 40 03-00 00 00 00 00 00 00 00 ..... @......... 01420000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 01420010 10 6d 99 00 00 00 00 00-00 00 01 40 50 f7 3d 03 .m.........@P.=. 01420020 03 00 00 00 08 00 00 00-00 01 00 00 00 00 00 00 ................ 01420030 1c 24 40 03 00 00 00 00-00 00 00 00 00 00 00 00 .$@.............

He insertado corchetes para los 52 bytes.

  • Los primeros cuatro bytes son la referencia a la tabla de métodos en 01309584.
  • Luego cuatro bytes para la longitud de la matriz.
  • A continuación están los números 0 a 9 (cada cuatro bytes).
  • Los últimos cuatro bytes son nulos. No estoy del todo seguro, pero supongo que debe ser donde se almacena la referencia a la matriz syncblock si la instancia se utiliza para el bloqueo.

Editar: Olvidé la longitud en la primera publicación.

El listado es ligeramente incorrecto porque, como señala romkyns, la instancia realmente comienza en la dirección - 4 y el primer campo es el Bloque sincronización.