Pourquoi la taille max de byte [] 2 GB - 57 b?

sur ma machine 64 bits, ce code C fonctionne:

new byte[2L * 1024 * 1024 * 1024 - 57]

mais celui-ci lance un OutOfMemoryException :

new byte[2L * 1024 * 1024 * 1024 - 56]

pourquoi?

je comprends que la taille maximale d'un objet géré est de 2 Go et que l'objet tableau que je crée contient plus que les octets que je veux. À savoir, il y a 4 octets (ou 8?) pour le nombre syncblock, 8 octets pour la référence MethodTable et 4 octets pour la taille du tableau. Ça fait 24 octets. y compris le padding, alors pourquoi je ne peux pas allouer un tableau avec 2G - 24 octets? Est-ce que la taille maximale est vraiment exactement 2 GB? Si c'est le cas, quel est le reste de 2 GO?

Note: je n'ai pas vraiment besoin d'allouer un tableau avec 2 millions d'octets. Et même si je l'ai fait, 56 octets est négligeable au-dessus. Et je pourrais facilement travailler autour de la limite en utilisant personnalisé BigArray<T> .

27
demandé sur svick 2011-07-08 00:26:46

2 réponses

vous avez besoin de 56 octets de overhead. Il est en fait 2 147 483 649-1 moins 56 pour la taille maximale. C'est pourquoi votre moins 57 fonctionne et moins 56 ne fonctionne pas.

comme Jon Skeet dit ici:

cependant, en termes pratiques, Je ne croyez que toute mise en œuvre soutient de tels tableaux. Le CCR a un limite par objet un peu court de 2 GO, donc même un tableau d'octets ne peut pas réellement ont 2147483648 éléments. Un peu de l'expérimentation montre que sur ma boîte, le plus grand tableau que vous pouvez créer est new byte [2147483591]. (Qui est sur le 64 bit .NET CLR; la version de Mono J'ai installé étouffe.)

Voir Aussi ce article D'information sur le même sujet. Il fournit le code suivant pour démontrer les tailles maximales et les frais généraux:

class Program
{
  static void Main(string[] args)
  {
    AllocateMaxSize<byte>();
    AllocateMaxSize<short>();
    AllocateMaxSize<int>();
    AllocateMaxSize<long>();
    AllocateMaxSize<object>();
  }

  const long twogigLimit = ((long)2 * 1024 * 1024 * 1024) - 1;
  static void AllocateMaxSize<T>()
  {
    int twogig = (int)twogigLimit;
    int num;
    Type tt = typeof(T);
    if (tt.IsValueType)
    {
      num = twogig / Marshal.SizeOf(typeof(T));
    }
    else
    {
      num = twogig / IntPtr.Size;
    }

    T[] buff;
    bool success = false;
    do
    {
      try
      {
        buff = new T[num];
        success = true;
      }
      catch (OutOfMemoryException)
      {
        --num;
      }
    } while (!success);
    Console.WriteLine("Maximum size of {0}[] is {1:N0} items.", typeof(T).ToString(), num);
  }
}

enfin, l'article a ceci à dire:

Si vous faites le calcul, vous verrez que les frais généraux pour allouer un tableau est de 56 octets. Il y a quelques octets de gauche à la fin, à cause de la taille des objets. Par exemple, 268 435 448 64 bits les nombres occupent 2,147,483,584 octets. Ajouter le tableau de 56 octets au-dessus vous donne 2,147,483,640, vous laissant 7 octets court de 2 gigaoctets.

Modifier:

mais attendez, il y a plus!

regardant autour et parlant avec Jon Skeet, il m'a montré un article qu'il a écrit sur de mémoire et cordes . Dans cet article, il fournit un tableau de tailles:

Type            x86 size            x64 size
object          12                  24
object[]        16 + length * 4     32 + length * 8
int[]           12 + length * 4     28 + length * 4
byte[]          12 + length         24 + length
string          14 + length * 2     26 + length * 2

M. Skeet poursuit en disant:

vous pourriez être pardonné de regarder les chiffres ci-dessus et penser que les "frais généraux" d'un objet est Douze octets en x86 et 24 de la version x64... mais ce n'est pas tout à fait droit.

et ceci:

  • il y a une" base " au-dessus de 8 octets par objet en x86 et 16 par objet en x64... étant donné que nous pouvons stocker un Int32 de données "réelles" dans x86 et ont toujours une taille d'objet de 12, et de même nous pouvons stocker deux Int32 de données réelles Dans x64 et ont encore un objet de x64.

  • il y a une taille "minimum" de 12 octets et 24 octets respectivement. Dans autrement dit, vous ne pouvez pas avoir un type qui est juste au dessus de vous. Notez comment la classe" vide " reprend la même taille comme créant des instances de Objet... il y a effectivement quelques chambre d'amis, parce que le CLR ne comme travailler sur un objet sans données. (À noter qu'un struct sans champs prend trop d'espace, même pour les variables locales.)

  • les objets x86 sont paddés à des limites de 4 octets; sur x64 c'est 8 octets (comme avant)

et finalement Jon Skeet a répondu à une question je lui ai demandé dans une autre question où il déclare (en réponse à la article InformIT je lui ai montré):

on dirait l'article que vous êtes se référer à inférer les frais généraux il suffit de partir de la limite, qui est ridicule de l'OMI.

donc pour répondre à votre question, les frais généraux réels est 24 octets avec 32 octets de pièce de rechange, de ce que je crois.

19
répondu Community 2017-05-23 11:46:37

une chose est sûre, c'est que vous ne pouvez pas avoir un nombre impair d'octets, il est généralement en multiples de la taille du mot natif qui est de 8 octets sur un processus de 64 bits. Donc vous pourriez ajouter 7 bytes supplémentaires au tableau.

3
répondu yan bellavance 2011-07-07 21:40:10