La taille d'un tableau limité par la limite supérieure de int (2147483647)?
-
05-09-2019 - |
Question
Bien sûr, ce sont de grands tableaux, mais par exemple, je ne peux pas le faire
// fails
bool[] BigArray = new BigArray[2147483648];
// also fails, cannot convert uint to int
ArrayList BigArrayList = new ArrayList(2147483648);
Alors, puis-je avoir de plus grands tableaux?
EDIT: Il était un Crible d'Atkin , vous le savez, donc je voulais vraiment grand: D
La solution
Chaque fois que vous travaillez avec un tableau ce grand, vous devriez probablement essayer de trouver une meilleure solution au problème. Mais cela étant dit, je vais encore tenter de répondre à votre question.
Comme mentionné dans cette article il est une limite de 2 Go sur un objet dans .NET. Pour tous x86, x64 et IA64.
Comme 32 bits d'exploitation Windows systèmes, il y a une limite de 2 Go sur la la taille d'un objet que vous pouvez créer en l'exécution d'une application gérée 64 bits sur un système d'exploitation Windows 64 bits.
Aussi, si vous définissez un tableau trop grand sur la pile, vous aurez un débordement de pile. Si vous définissez le tableau sur le tas, il essaiera d'allouer tout dans un grand bloc continu. Il serait préférable d'utiliser une ArrayList qui a l'allocation dynamique implicite sur le tas. Cela ne vous permettra pas de dépasser les 2 Go, mais vous permettra sans doute de se rapprocher de lui.
Je pense que la limite de taille de la pile sera plus grand que si vous utilisez un x64 ou de l'architecture IA64 et système d'exploitation. L'utilisation x64 ou IA64 vous aurez la mémoire allouable 64 bits au lieu de 32 bits.
Si vous n'êtes pas en mesure d'allouer la liste de tableau à la fois, vous pouvez probablement l'affecter dans certaines régions.
Utilisation d'une liste de tableau et en ajoutant 1 objet à la fois sur une machine Windows x64 2008 avec 6 Go de RAM, le plus que je peux obtenir le ArrayList est de taille: 134217728. Je pense vraiment que vous devez trouver une meilleure solution pour votre problème ne pas utiliser autant de mémoire. Peut-être écrire dans un fichier au lieu d'utiliser la RAM.
Autres conseils
La limite de tableau est, autant que je sache, fixé comme int32 même sur 64 bits. Il y a un plafond sur la taille maximale d'un seul objet. Cependant, vous pourriez avoir une belle grande gamme en dents de scie assez facilement.
Pire encore; parce que les références sont plus grandes en x64, pour les tableaux de type ref vous obtenez en fait moins dans un seul tableau.
J'ai reçu un certain nombre de questions que pourquoi la version 64 bits du 2.0 runtime .Net a encore un maximum de tableau tailles limitées à 2 Go. Étant donné que semble être un sujet de fin I un peu de fond compris et discussion des options pour obtenir cette limitation était en ordre.
Tout d'abord quelques arrière-plan; dans le 2,0 version du moteur d'exécution .Net (CLR) nous pris une décision de conception consciente de maintenir la taille de l'objet maximum autorisé dans le GC Heap à 2 Go, même sur la version 64 bits de l'exécution. C'est le même que le courant 1.1 la mise en œuvre du CLR 32 bits, mais vous serait difficile à gérer effectivement d'allouer un 2 Go objet sur le CLR 32 bits car la l'espace d'adressage virtuel est tout simplement trop fragmenté pour trouver une façon réaliste de 2 Go trou. Généralement, les gens ne sont pas particulièrement préoccupé par la création types qui seraient> 2 Go lorsque instancié (ou ailleurs à proximité), cependant, puisque les tableaux ne sont que type particulier de type managé qui sont créé au sein du tas managé ils souffrent également de cette limitation.
Il convient de noter que dans .NET 4.5 taille de la mémoire limite est éventuellement retiré par le gcAllowVeryLargeObjects drapeau, cependant, cela ne change pas le maximum dimension taille. Le point clé est que si vous avez des tableaux d'un type personnalisé, ou des tableaux multidimensionnels, vous pouvez maintenant aller au-delà de 2 Go en taille de la mémoire.
Vous n'avez pas besoin d'un tableau que tout grand.
Lorsque votre méthode se heurte à des problèmes de ressources, ne regardez pas seulement à la façon d'accroître les ressources, regardez la méthode aussi. :)
Voici une classe qui utilise un tampon de 3 Mo pour calculer les nombres premiers en utilisant le tamis d'Eratosthène. La classe conserve la trace de la distance que vous avez calculé les nombres premiers, et lorsque la plage doit être élargi, il crée un tampon pour tester un autre 3 millions de numéros.
Il maintient les nombres premiers trouvés dans une liste, et lorsque la plage est étendu les nombres premiers previos sont utilisés pour écarter des numéros dans la mémoire tampon.
Je fait quelques tests, et un tampon d'environ 3 Mo est la plus efficace.
public class Primes {
private const int _blockSize = 3000000;
private List<long> _primes;
private long _next;
public Primes() {
_primes = new List<long>() { 2, 3, 5, 7, 11, 13, 17, 19 };
_next = 23;
}
private void Expand() {
bool[] sieve = new bool[_blockSize];
foreach (long prime in _primes) {
for (long i = ((_next + prime - 1L) / prime) * prime - _next;
i < _blockSize; i += prime) {
sieve[i] = true;
}
}
for (int i = 0; i < _blockSize; i++) {
if (!sieve[i]) {
_primes.Add(_next);
for (long j = i + _next; j < _blockSize; j += _next) {
sieve[j] = true;
}
}
_next++;
}
}
public long this[int index] {
get {
if (index < 0) throw new IndexOutOfRangeException();
while (index >= _primes.Count) {
Expand();
}
return _primes[index];
}
}
public bool IsPrime(long number) {
while (_primes[_primes.Count - 1] < number) {
Expand();
}
return _primes.BinarySearch(number) >= 0;
}
}
Je crois que même dans un CLR 64 bits, il y a une limite de 2 Go (1 Go ou peut-être - je ne me souviens pas exactement) par objet. Cela vous empêcher de créer un ensemble plus grand. Le fait que Array.CreateInstance ne prend arguments Int32 pour les tailles suggère aussi.
Sur une note plus générale, je pense que si vous avez besoin que des tableaux grand, vous devriez vraiment changer la façon dont vous vous approchez le problème.
Je suis très bien un débutant avec C # (à savoir l'apprendre cette semaine), donc je ne suis pas sûr des détails exacts de la façon dont ArrayList est mis en œuvre. Cependant, je suppose que vous n'avez pas défini un type pour l'exemple ArrayList, alors le tableau serait réparti comme un tableau de références d'objets. Cela pourrait signifier que vous allouez effectivement 4-8Gb de la mémoire en fonction de l'architecture.
Selon MSDN , l'index de tableau d'octets ne peut pas être supérieure à 2147483591. pour .NET avant 4.5, il était aussi une limite de mémoire pour un tableau. Dans .NET 4.5 ce maximum est le même, mais pour d'autres types, il peut être jusqu'à 2.146.435.071.
Voici le code d'illustration:
static void Main(string[] args)
{
// -----------------------------------------------
// Pre .NET 4.5 or gcAllowVeryLargeObjects unset
const int twoGig = 2147483591; // magic number from .NET
var type = typeof(int); // type to use
var size = Marshal.SizeOf(type); // type size
var num = twoGig / size; // max element count
var arr20 = Array.CreateInstance(type, num);
var arr21 = new byte[num];
// -----------------------------------------------
// .NET 4.5 with x64 and gcAllowVeryLargeObjects set
var arr451 = new byte[2147483591];
var arr452 = Array.CreateInstance(typeof(int), 2146435071);
var arr453 = new byte[2146435071]; // another magic number
return;
}