2009-01-28 8 views
38

Quelle est la disposition de la mémoire d'un tableau .NET?Disposition de la mémoire d'un tableau .NET

Prenez par exemple ce tableau:

Int32[] x = new Int32[10]; 

Je comprends que la majeure partie du tableau est comme ceci:

0000111122223333444455556666777788889999 

où chaque caractère est un octet, et les chiffres correspondent à des indices en le tableau.

De plus, je sais qu'il ya une référence de type, et un indice de syncblock-pour tous les objets, de sorte que le ci-dessus peut être ajustée à ceci:

ttttssss0000111122223333444455556666777788889999 
     ^
     +- object reference points here 

De plus, la longueur du tableau doit être stocké, donc c'est peut-être plus correct:

ttttssssllll0000111122223333444455556666777788889999 
     ^
     +- object reference points here 

Est-ce que c'est complet? Y a-t-il plus de données dans un tableau? La raison pour laquelle je pose cette question est que nous essayons d'estimer la quantité de mémoire qu'une ou plusieurs représentations en mémoire d'un corpus de données assez volumineux prendront et que la taille des tableaux varie beaucoup, les frais généraux peuvent avoir un impact important dans une solution, mais peut-être pas autant dans l'autre.

Donc, fondamentalement, pour un tableau, combien y a-t-il de frais généraux, c'est essentiellement ma question. Et avant que les tableaux soient mauvais squad se réveille, cette partie de la solution est une construction statique une fois-référence-souvent type de chose donc l'utilisation de listes extensibles n'est pas nécessaire ici.

+1

Juste un petit mot: le syncblock vient avant la référence de type de méthode. La variable contient un pointeur (référence) à la référence de type de méthode ('tttt' ci-dessus), en ignorant la partie syncblock. La disposition ressemble en fait à 'ssssttttllll000011 ... 9999NULL' pour les tableaux sans dimensions spécifiques ou limites inférieures spécifiques. – Abel

Répondre

8

Bonne question. J'ai trouvé this l'article qui contient des diagrammes de bloc pour les types de valeur et les types de référence. Voir aussi ce article dans lequel les États Ritcher:

[snip] chaque tableau a quelques informations supplémentaires au-dessus associée à il. Cette information contient le rang du tableau (nombre de dimensions), les limites inférieures pour chaque dimension de le tableau (presque toujours 0), et la longueur de chaque dimension. L'en-tête contient également le type de chaque élément dans le tableau.

+2

Puis-je suggérer d'ajouter l'article "Arrays UNDOCUMENTED" de Code Project à cette solution: http://www.codeproject.com/KB/dotnet/arrays.aspx –

+2

Le livre dont provient ce snip s'appelle "CLR via C#" et c'est un livre fantastique. –

+0

Je ne suis pas d'accord avec SnOrfus - superbe livre. – ng5000

0

Un objet tableau devrait stocker combien de dimensions il a et la longueur de chaque dimension. Il y a donc au moins un élément de plus à ajouter à votre modèle.

5

Bonne question! Je voulais voir par moi-même, et il me semblait une bonne occasion d'essayer Cordbg.exe ...

Il semble que pour les tableaux simples entiers, le format est:

ssssllll000011112222....nnnn0000 

où s est la bloc de synchronisation, l la longueur du tableau, puis les éléments individuels. Il semble qu'il y ait un 0 finalement à la fin, je ne suis pas sûr de savoir pourquoi.

Pour les tableaux multidimensionnels:

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

où s est le bloc de synchronisation, t le nombre total d'éléments, L1 la longueur de la première dimension, L2 la longueur de la deuxième dimension, puis deux zéros ?, suivi par tous les éléments séquentiellement, et enfin un zéro à nouveau.

Les tableaux d'objets sont traités en tant que tableau d'entiers, les contenus sont des références cette fois. Les tableaux dentelés sont des tableaux d'objets où les références pointent vers d'autres tableaux.

17

Une façon d'examiner cela est de regarder le code dans WinDbg. Donc, vu le code ci-dessous, voyons comment cela apparaît sur le tas.

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

La première chose à faire est de localiser l'instance. Comme je l'ai fait un local dans Main(), il est facile de trouver l'adresse de l'instance.

De l'adresse, nous pouvons vider l'instance réelle, ce qui nous donne:

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 

Cela nous dit qu'il est de notre gamme Int32 avec 10 éléments et une taille totale de 52 octets.

Jetons la mémoire où se trouve l'instance.

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 [email protected]=. 
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 [email protected] 

J'ai inséré des parenthèses pour les 52 octets.

  • Les quatre premiers octets sont la référence à la table de la méthode à 01309584.
  • Puis quatre octets pour la longueur du tableau.
  • Après cela sont les nombres de 0 à 9 (chaque quatre octets).
  • Les quatre derniers octets sont null. Je ne suis pas tout à fait sûr, mais je suppose que cela doit être là où la référence au tableau syncblock est stockée si l'instance est utilisée pour le verrouillage.

Editer: Longueur oubliée en première publication.

La liste est légèrement incorrecte car, comme le souligne romkyns, l'instance commence réellement à l'adresse - 4 et le premier champ est le Syncblock.

+1

Les quatre derniers octets sont en fait en dehors de ce tableau. C'est parce que le pointeur que vous obtenez est décalé de 4 dans l'objet; l'index syncblock arrive en premier à offset -4. [référence] (http://msdn.microsoft.com/fr-fr/magazine/cc163791.aspx) –

+0

"Les quatre premiers octets sont la référence à la table de méthode au 01309510." - ne devrait pas être "au 01309584"? – stej

+0

@stej oui il devrait. Merci d'avoir signalé l'erreur. –