Pregunta

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

Tome 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 la matriz.

Además, sé que hay una referencia de tipo y un índice de bloqueo de sincronización para 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 almacenarse, por lo que quizás esto sea más correcto:

ttttssssllll0000111122223333444455556666777788889999
        ^
        +- object reference points here

¿Esto está completo? ¿Hay más datos en una matriz?

La razón por la que pregunto 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 un gran impacto en una solución, pero quizás no tanto en la otra.

Entonces, básicamente, para una matriz, cuánta sobrecarga hay, esa es básicamente mi pregunta.

Y antes de que el equipo arrays sea malo se despierte, esta parte de la solución es un tipo estático de compilación de una vez referencia, a menudo, por lo que no es necesario usar listas que puedan crecer aquí.

¿Fue útil?

Solución

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

  

[snip] cada matriz tiene algo adicional   información general asociada con   eso. 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 el   longitud de cada dimensión. La sobrecarga   también contiene el tipo de cada elemento   en la matriz.

Otros consejos

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 he hecho de esto un local en Main(), es fácil encontrar la dirección de la instancia.

Desde la dirección podemos volcar la instancia real, 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.

Volquemos 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.
  • Entonces cuatro bytes para la longitud de la matriz.
  • A continuación se encuentran los números del 0 al 9 (cada uno de cuatro bytes).
  • Los últimos cuatro bytes son nulos. No estoy completamente seguro, pero supongo que debe ser donde se almacena la referencia a la matriz de bloque de sincronización 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 en realidad comienza en la dirección 4 y el primer campo es el Bloque de sincronización.

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

Parece que para matrices enteras 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é.

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 de 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 irregulares son matrices de objetos donde las referencias apuntan a otras matrices.

Un objeto de matriz debería 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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top