J'ai une application C # assez simple qui construit une grande hache. Les clés de cette hache sont des chaînes et les valeurs sont des INTS. P>
Le programme fonctionne bien jusqu'à ce que environ 10,3 millions d'articles soient ajoutés à la haquetable, lorsqu'une erreur de mémoire est lancée sur la ligne qui ajoute un élément au hastable. P>
Selon le gestionnaire de tâches, mon programme n'utilise que 797 Mo de mémoire et il y a encore plus de 2 Go. C'est une machine de 32 bits. Je ne sais donc que seulement 2 Go peut être utilisé par un processus, mais cela laisse encore environ 1,2 Go que la haquetable devrait pouvoir se développer. P>
Pourquoi une erreur de mémoire de mémoire serait-elle lancée? P>
7 Réponses :
Il est probablement dû à la fragmentation de la mémoire: vous avez toujours une mémoire libre mais pas contiguë. La mémoire est divisée dans les pages em>, généralement de 4 ko de taille, donc si vous allouez 4 Mo, vous aurez besoin de 1024 pages de mémoire contiguës dans votre espace d'adressage em> (ils n'ont pas été < em> physiquement em> contigus comme la mémoire est virtualisé par processus). P>
Cependant, la mémoire de la haquetable n'a pas été contiguë (sauf si elle est très mal implémentée), alors peut-être que c'est une limite du gestionnaire de mémoire ... p>
En théorie, vous obtenez 2 Go pour le processus, mais la réalité est qu'elle est 2 Go de mémoire contiguë, donc si la mémoire de votre processus est fragmentée, vous obtenez moins que cela. P>
En outre, je soupçonne que la table de hachage, comme la plupart des structures de données par défaut, la taille de la taille aura besoin de croître, entraînant ainsi une croissance énorme lorsque l'élément de pointe est ajouté. P>
Si vous connaissez la taille qu'il doit être à l'avance (ou avoir une sur-estimation raisonnable), cela peut aider à spécifier la capacité du constructeur. P>
Alternativement si ce n'est pas crucial que c'est en mémoire, une sorte de solution de base de données peut être meilleure et vous donner plus de flexibilité si cela atteint le point qu'il ne peut pas correspondre à la mémoire. P>
Pas exactement: chaque processus a obtenu son 2 Go de mémoire virtuelle contiguë de 2 Go. La fragmentation est à l'intérieur i> le processus, car deux pages de mémoire contiguës dans votre processus peuvent en réalité être contiguë au noyau.
Merci ... Je l'ai mis à nouveau courir avec une capacité de 17 millions, et nous verrons comment ça se passe. Les données proviennent de la base de données, mais je ne peux pas exécuter la procédure elle-même là-bas que des requêtes récursives sont très lentes. Je pourrais insérer chaque instance de (élément, noeud) dans la base de données pour pouvoir traiter après, mais je m'attends à ce que ce soit très lent en raison des vitesses de réseau
@Lorenzo Merci, mis à jour pour refléter la fragmentation de la mémoire dans le processus et non le système.
@Paul Si cela ne fonctionne pas et la vitesse du réseau est le problème avec l'utilisation de la base de données actuelle, une base de données temporaire locale légère avec quelque chose comme SQLite peut-elle être appropriée?
@ Davy8: +1 pour vous atteindre 10k!
Vous devez utiliser quelque chose comme des hibrides entre tableau et liste liée. Étant donné que la liste liée prend plus de mémoire par élément que la matrice, mais la matrice nécessite un espace mémoire continu. P>
Utilisez Explorateur de processus (www.sysinternals.com) et consultez l'espace d'adressage virtuel de votre processus. Contrairement aux «octets privés» (qui correspond à la quantité de mémoire prise par le processus), l'espace d'adressage virtuel indique l'adresse de mémoire la plus élevée en cours d'utilisation. Si la fragmentation est élevée, ce sera beaucoup plus élevé que les "octets privés". P>
Si votre application a vraiment besoin de beaucoup de mémoire: p>
Vous regardez simplement la mauvaise colonne. Regardez la colonne "Taille de validation", celle-ci devrait être d'environ 2 Go. P>
HTTP : //windows.microsoft.com/en-us/windows-vista/what-do-the-task-manager-Memory-Columns-Mean P>
C'est Windows XP ... Je ne pense pas que cela a une "taille de commettre" dans le chef de travail
C'est une réponse agréable, mais la question devient maintenant: pourquoi la taille de commettre est tellement plus grande que l'utilisation de la mémoire réelle?
Lorenzo: "Taille de validation" est la quantité de mémoire réservée à une utilisation par l'application (c'est-à-dire une commande d'allocation de mémoire d'une mémoire a été exécutée) - ne signifie pas nécessairement que c'est en réalité utilisé. "Set de travail privé" est la quantité de mémoire qui a été attribuée à la fois / et / utilisée par le processus, qui ne peut pas être partagée avec d'autres processus.
@Paul, ok, puisque je n'ai pas de machine XP pour vérifier, je ne sais pas sur quelle version il est disponible. Quoi qu'il en soit, la chose est que seules les pages de mémoire attribuées à l'application comptent en tant que jeu de travail, les pages qui sont échangées ou cessées ne sont pas comptées. Les fenêtres semblent préférer parfois favoriser le cache sur un échange, ce qui signifie que votre application peut Soyez partiellement échangé, même si vous pensez qu'il y a une mémoire gratuite disponible.
Le programme que vous utilisez a des ressources limitées grâce au débogueur Visual Studio essayant de garder une trace de tout ce que vous faites dans votre application (points d'arrêt, références, la pile, etc.).
En plus de cette , vous aurez peut-être plus de choses qui est toujours indisposée que vous ne le pensez - le collecteur des ordures est balancé et collecte de gros objets très em> lentement. p> +-------+
| large | collected less often (~1/10+ cycles)
+-+-------+-+ |
| medium | |
+-+-----------+-+ V
| small | collected more often (~1/3 cycles)
+---------------+
Permettez-moi de clarifier - en mode de débogage, non pas en mode de libération.
J'ai résolu ma version de ce problème en décochez la case "Préférer 32 bits" dans la page Propriétés du projet de l'EXE sous l'onglet Construction P>
BTW, j'espère que vous comprenez cela n'a rien à voir avec C #?
@John: Mais peut-être / probablement c'est .NET connexe.
@Lorenzo: C'est mon point. Pas c #, mais plutôt .net
Pourquoi avez-vous besoin de 10,3 millions d'articles dans une haquetable au moment de l'exécution?
Oui, je comprends que c'est une chose .NET Framework et non une chose C #. J'ai besoin de millions d'articles dans une hache car je marche quelques millions d'articles dans un grand arbre et je dois stocker la distribution de l'une de leurs propriétés à chaque nœud. Je pensais que cela préférable d'utiliser une grande hache que des milliers de plus petits.
Cela ne signifie pas toujours qu'il n'y a plus de mémoire. Parfois, j'ai mon application jette une exception exceptionnelle juste pour désordre avec l'équipe des opérations: P
@Paul: avec précision quelle classe "Hashtable" utilisez-vous?
hashtable code>? Vous devriez essayer diverses autres collections comme
Dictionary code> à la place.
J'utilise Hashtable. Je vais donner un dictionnaire un essai.