Voici mon code:
int size = 100000000;
double sizeInMegabytes = (size * 8.0) / 1024.0 / 1024.0; //762 mb
double[] randomNumbers = new double[size];
Exception: une exception de type «System.OutOfMemoryException» a été levée.
J'ai 4 Go de mémoire sur cette machine 2,5 Go sont gratuits lorsque je démarre cette course, il y a clairement assez d'espace sur le PC pour gérer les 762 Mo de 100000000 nombres aléatoires. J'ai besoin de stocker autant de nombres aléatoires que possible compte tenu de la mémoire disponible. Lorsque je passerai en production, il y aura 12 Go sur la boîte et je veux en profiter.
Le CLR me contraint-il à une mémoire maximale par défaut pour commencer? et comment demander plus?
Mettre à jour
Je pensais que diviser cela en petits morceaux et ajouter progressivement à mes besoins en mémoire aiderait si le problème était dû à la fragmentation de la mémoire , mais ce n'est pas le cas, je ne peux pas dépasser une taille totale de ArrayList de 256 Mo, peu importe ce que je fais en modifiant blockSize .
private static IRandomGenerator rnd = new MersenneTwister();
private static IDistribution dist = new DiscreteNormalDistribution(1048576);
private static List<double> ndRandomNumbers = new List<double>();
private static void AddNDRandomNumbers(int numberOfRandomNumbers) {
for (int i = 0; i < numberOfRandomNumbers; i++) {
ndRandomNumbers.Add(dist.ICDF(rnd.nextUniform()));
}
}
De ma méthode principale:
int blockSize = 1000000;
while (true) {
try
{
AddNDRandomNumbers(blockSize);
}
catch (System.OutOfMemoryException ex)
{
break;
}
}
double arrayTotalSizeInMegabytes = (ndRandomNumbers.Count * 8.0) / 1024.0 / 1024.0;
Réponses:
Vous voudrez peut-être lire ceci: « « Mémoire insuffisante »ne fait pas référence à la mémoire physique » par Eric Lippert.
Bref, et très simplifié, «Out of memory» ne signifie pas vraiment que la quantité de mémoire disponible est trop petite. La raison la plus courante est que dans l'espace d'adressage actuel, il n'y a pas de partie contiguë de mémoire suffisamment grande pour servir l'allocation souhaitée. Si vous avez 100 blocs de 4 Mo chacun, cela ne vous aidera pas lorsque vous aurez besoin d'un bloc de 5 Mo.
Points clés:
la source
Vérifiez que vous créez un processus 64 bits et non un processus 32 bits, qui est le mode de compilation par défaut de Visual Studio. Pour ce faire, faites un clic droit sur votre projet, Propriétés -> Construire -> cible de la plateforme: x64. Comme tout processus 32 bits, les applications Visual Studio compilées en 32 bits ont une limite de mémoire virtuelle de 2 Go.
Les processus 64 bits n'ont pas cette limitation, car ils utilisent des pointeurs 64 bits, donc leur espace d'adressage maximum théorique (la taille de leur mémoire virtuelle) est de 16 exaoctets (2 ^ 64). En réalité, Windows x64 limite la mémoire virtuelle des processus à 8 To. La solution au problème de limite de mémoire est alors de compiler en 64 bits.
Cependant, la taille de l'objet dans Visual Studio est toujours limitée à 2 Go, par défaut. Vous pourrez créer plusieurs baies dont la taille combinée sera supérieure à 2 Go, mais vous ne pouvez pas par défaut créer des baies de plus de 2 Go. Espérons que si vous souhaitez toujours créer des tableaux de plus de 2 Go, vous pouvez le faire en ajoutant le code suivant à votre fichier app.config:
la source
Vous n'avez pas de bloc continu de mémoire pour allouer 762 Mo, votre mémoire est fragmentée et l'allocateur ne peut pas trouver un trou assez grand pour allouer la mémoire nécessaire.
la source
Comme vous l'avez probablement compris, le problème est que vous essayez d'allouer un gros bloc de mémoire contigu, qui ne fonctionne pas en raison de la fragmentation de la mémoire. Si j'avais besoin de faire ce que vous faites, je ferais ce qui suit:
Ensuite, pour obtenir un index particulier que vous utiliseriez
randomNumbers[i / sizeB][i % sizeB]
.Une autre option si vous accédez toujours aux valeurs dans l'ordre peut être d'utiliser le constructeur surchargé pour spécifier la valeur de départ. De cette façon, vous obtiendrez un nombre semi-aléatoire (comme le
DateTime.Now.Ticks
) stockez-le dans une variable, puis chaque fois que vous commencez à parcourir la liste, vous créez une nouvelle instance aléatoire en utilisant la graine d'origine:Il est important de noter que si le blog lié à la réponse de Fredrik Mörk indique que le problème est généralement dû à un manque d' espace d'adressage, il ne répertorie pas un certain nombre d'autres problèmes, comme la limite de taille d'objet CLR de 2 Go (mentionnée dans un commentaire de ShuggyCoUk sur le même blog), passe sous silence la fragmentation de la mémoire et ne mentionne pas l'impact de la taille du fichier d'échange (et comment il peut être résolu avec l'utilisation de la
CreateFileMapping
fonction ).La limitation de 2 Go signifie qu'elle
randomNumbers
doit être inférieure à 2 Go. Puisque les tableaux sont des classes et ont eux-mêmes une surcharge, cela signifie qu'un tableau dedouble
devra être plus petit que 2 ^ 31. Je ne sais pas à quel point la longueur devrait être inférieure à 2 ^ 31, mais les frais généraux d'un tableau .NET?indique 12 à 16 octets.La fragmentation de la mémoire est très similaire à la fragmentation du disque dur. Vous pouvez avoir 2 Go d'espace d'adressage, mais lorsque vous créez et détruisez des objets, il y aura des écarts entre les valeurs. Si ces espaces sont trop petits pour votre gros objet et qu'un espace supplémentaire ne peut pas être demandé, vous obtiendrez le
System.OutOfMemoryException
. Par exemple, si vous créez 2 millions d'objets de 1 024 octets, vous utilisez 1,9 Go. Si vous supprimez chaque objet dont l'adresse n'est pas un multiple de 3, vous utiliserez 0,6 Go de mémoire, mais il sera réparti dans l'espace d'adressage avec des blocs ouverts de 2024 octets entre les deux. Si vous avez besoin de créer un objet de 0,2 Go, vous ne pourrez pas le faire car il n'y a pas de bloc assez grand pour le ranger et un espace supplémentaire ne peut pas être obtenu (en supposant un environnement 32 bits). Les solutions possibles à ce problème sont des choses comme l'utilisation d'objets plus petits, la réduction de la quantité de données que vous stockez en mémoire ou l'utilisation d'un algorithme de gestion de la mémoire pour limiter / empêcher la fragmentation de la mémoire. Il convient de noter qu'à moins que vous ne développiez un programme volumineux qui utilise une grande quantité de mémoire, cela ne sera pas un problème. Aussi,Étant donné que la plupart des programmes demandent de la mémoire de travail au système d'exploitation et ne demandent pas de mappage de fichiers, ils seront limités par la RAM du système et la taille du fichier d'échange. Comme indiqué dans le commentaire de Néstor Sánchez (Néstor Sánchez) sur le blog, avec du code géré comme C #, vous êtes bloqué sur la limitation RAM / fichier de page et l'espace d'adressage du système d'exploitation.
C'était beaucoup plus long que prévu. Espérons que cela aide quelqu'un. Je l'ai posté parce que je suis tombé sur l'
System.OutOfMemoryException
exécution d'un programme x64 sur un système avec 24 Go de RAM, même si mon tableau ne contenait que 2 Go de contenu.la source
Je déconseille l'option de démarrage Windows / 3GB. En dehors de tout le reste (c'est exagéré de faire ça pour un application mal comportée, et cela ne résoudra probablement pas votre problème de toute façon), cela peut causer beaucoup d'instabilité.
De nombreux pilotes Windows ne sont pas testés avec cette option, donc plusieurs d'entre eux supposent que les pointeurs en mode utilisateur pointent toujours vers les 2 Go inférieurs de l'espace d'adressage. Ce qui signifie qu'ils peuvent casser horriblement avec / 3 Go.
Cependant, Windows limite normalement un processus 32 bits à un espace d'adressage de 2 Go. Mais cela ne signifie pas que vous devez vous attendre à pouvoir allouer 2 Go!
L'espace d'adressage est déjà jonché de toutes sortes de données allouées. Il y a la pile et tous les assemblys chargés, les variables statiques, etc. Il n'y a aucune garantie qu'il y aura 800 Mo de mémoire contiguë non allouée n'importe où.
Allouer 2 blocs de 400 Mo serait probablement mieux. Ou 4 morceaux de 200 Mo. Des allocations plus petites sont beaucoup plus faciles à trouver dans un espace mémoire fragmenté.
Quoi qu'il en soit, si vous allez quand même déployer cela sur une machine de 12 Go, vous voudrez l'exécuter en tant qu'application 64 bits, ce qui devrait résoudre tous les problèmes.
la source
Le passage de 32 à 64 bits a fonctionné pour moi - cela vaut la peine d'essayer si vous êtes sur un PC 64 bits et qu'il n'a pas besoin de porter.
la source
Si vous avez besoin de structures aussi volumineuses, vous pouvez peut-être utiliser des fichiers mappés en mémoire. Cet article pourrait s'avérer utile: http://www.codeproject.com/KB/recipes/MemoryMappedGenericArray.aspx
LP, Dejan
la source
Windows 32 bits a une limite de mémoire de processus de 2 Go. L'option de démarrage / 3 Go que d'autres ont mentionnée rendra ces 3 Go avec seulement 1 Go restant pour l'utilisation du noyau du système d'exploitation. De manière réaliste, si vous souhaitez utiliser plus de 2 Go sans tracas, un système d'exploitation 64 bits est nécessaire. Cela permet également de résoudre le problème selon lequel, même si vous disposez de 4 Go de RAM physique, l'espace d'adressage requis pour la carte vidéo peut rendre une partie importante de cette mémoire inutilisable - généralement environ 500 Mo.
la source
Plutôt que d'allouer un tableau massif, pourriez-vous essayer d'utiliser un itérateur? Celles-ci sont exécutées en différé, ce qui signifie que les valeurs sont générées uniquement lorsqu'elles sont demandées dans une instruction foreach; vous ne devriez pas manquer de mémoire de cette façon:
Ce qui précède générera autant de nombres aléatoires que vous le souhaitez, mais ne les générera que lorsqu'ils sont demandés via une instruction foreach. Vous ne manquerez pas de mémoire de cette façon.
Sinon, si vous devez tous les avoir au même endroit, stockez-les dans un fichier plutôt qu'en mémoire.
la source
Eh bien, j'ai un problème similaire avec un grand ensemble de données et essayer de forcer l'application à utiliser autant de données n'est pas vraiment la bonne option. Le meilleur conseil que je puisse vous donner est de traiter vos données en petits morceaux si cela est possible. Parce que traiter autant de données, le problème reviendra tôt ou tard. De plus, vous ne pouvez pas connaître la configuration de chaque machine qui exécutera votre application, il y a donc toujours un risque que l'exception se produise sur un autre PC.
la source
J'ai eu un problème similaire, il était dû à un StringBuilder.ToString ();
la source
Convertissez votre solution en x64. Si vous rencontrez toujours un problème, accordez une longueur maximale à tout ce qui lève une exception comme ci-dessous:
la source
Si vous n'avez pas besoin du processus d'hébergement Visual Studio:
Décochez l'option: Projet-> Propriétés-> Déboguer-> Activer le processus d'hébergement Visual Studio
Et puis construisez.
Si vous rencontrez toujours le problème:
Accédez à Projet-> Propriétés-> Événements de construction-> Ligne de commande d'événement post-construction et collez ce qui suit:
Maintenant, construisez le projet.
la source
Augmentez la limite de processus Windows à 3 Go. (via boot.ini ou Vista boot manager)
la source