2010-09-07 6 views
31

Je suis en train de tester la taille d'une collection dans .Net. Techniquement, n'importe quel objet de collection peut atteindre la taille de la mémoire physique. Puis j'ai testé le code suivant dans un serveur, qui a 16 Go de mémoire, exécutant Windows 2003 Server et Visual Studio 2008. J'ai testé le code F # et C#, et j'ai regardé le gestionnaire des tâches pendant l'exécution. Je peux voir que, après la croissance de la mémoire de 2 Go, le programme s'est écrasé avec une exception de mémoire insuffisante. J'ai défini la plate-forme cible sur x64 dans la page de propriétés. J'ai fait un même test à la bibliothèque de la collection C5Une très grande collection dans .Net provoque une exception de mémoire insuffisante

open System.Collections.Generic 

let d = new Dictionary<int, int>() 

for i=1 to 1000000000 do 
    d.Add(i,i) 
Le résultat est que le dictionnaire en C5 pourrait utiliser toute la mémoire. Le code utilise C5:

let d = C5.HashDictionary<int, int>() 
for i=1 to 1000000000 do 
    d.Add(i,i) 

Quelqu'un sait pourquoi?

+12

mémoire physique n'a rien à voir avec des tailles maximales. Windows utilise la gestion de la mémoire virtuelle depuis plus d'une décennie maintenant. Vous pouvez avoir des objets qui sont loin, beaucoup plus grande que la mémoire physique disponible car bien sûr, la mémoire physique disponible peut être * zéro * lorsqu'un nouveau processus est créé. C'est tout le * point * de la mémoire virtuelle; cette mémoire physique est juste une optimisation des performances de la mémoire virtuelle. (S'il n'y a pas assez de mémoire physique pour contenir le jeu de travail, la performance se dégrade, mais tout devrait fonctionner *.) –

+2

@EricLippert Compris et accepté, mais qu'en est-il de l'inverse ... Devriez-vous obtenir un MOO quand il y a de la mémoire physique? disponible? (En supposant que c'est un vrai MOO pas un trop grand nombre de poignées/problème similaire). Dans ce cas, il semble que la limite imposée par le CLR était le problème, mais cela ne signifie que la question OP est un bon à mon avis – Basic

Répondre

42

Microsoft CLR a une limite de taille d'objet maximale de 2 Go, même la version 64 bits. (Je ne suis pas sûr si cette limite est également présente dans d'autres implémentations telles que Mono.)

La limitation s'applique à chaque objet simple - pas la taille totale de tous les objets - ce qui signifie que c'est relativement facile pour contourner le problème en utilisant une collection composite de quelque sorte.

Il y a une discussion et quelques exemples de code ici ...

Il semble y avoir très peu de documentation officielle qui fait référence à cette limite. Il s'agit, après tout, d'un détail de mise en œuvre du CLR actuel. La seule mention que je connais est on this page:

Lorsque vous exécutez un 64 bits géré application sur un ordinateur Windows système d'exploitation 64 bits, vous pouvez créer un objet de pas plus de 2 gigaoctets (GB).

+0

+1, @Yin: Cet article pourrait vous aider à circuler, http: // blogs. msdn.com/b/joshwil/archive/2005/08/10/450202.aspx –

+0

@KMan: Ha. Je l'ai édité en quelques secondes avant que votre commentaire est apparu :) – LukeH

+1

Et votre poste entier est venu quelques secondes avant le mien :) –

10

Et pour être clair, un dictionnaire utilise un seul tableau pour ajouter les paires. Il est cultivé (doublé?) Chaque fois qu'il est plein. Quand il y a 512 millions d'objets, sa taille est de 2 Go (avec un pointeur d'objet de 32 bits, et en supposant une distribution parfaite). Ajouter un élément de plus fait que le dictionnaire tente de doubler la taille du tableau. Boom.

Le HashDictionary C5 utilise un hachage linéaire et utilise probablement un tableau de compartiments contenant chacun plusieurs éléments (16?). Il devrait rencontrer le même problème (beaucoup) plus tard.

+0

grand commentaire! Merci. –

+0

btw, l'implémentation dans c5 est linéaire - pour chaque valeur de hachage, c'est une liste chaînée. –

+0

Ah, merci. Le papier de hachage linéaire original conseille contre cela. –

18

Dans les versions de .NET antérieures à la version 4.5, la taille maximale de l'objet est de 2 Go. À partir de 4.5, vous pouvez allouer des objets plus grands si gcAllowVeryLargeObjects est activé. Notez que la limite pour string n'est pas affectée, mais les «tableaux» doivent également couvrir les «listes», car les listes sont sauvegardées par des tableaux.

-1

Le "permettre les grands objets" aidera seulement à se débarrasser de l'exception de MOO.

Lorsque vous avez besoin de stocker beaucoup d'objets, le problème que vous verrez est CP stalles (pauses).Ce que nous avons fait est de "cacher" des données du GC, qui s'est transformé en une solution très pratique.

Voir ceci: https://www.infoq.com/articles/Big-Memory-Part-3

Vous pouvez utiliser le cache qui fonctionne comme un dictionnaire: https://github.com/aumcode/nfx/tree/master/Source/NFX/ApplicationModel/Pile

voir la section de mise en cache

Questions connexes