Faire face à de très grandes listes sur x86

Je dois travailler avec de grandes listes de flotteurs, mais je respecte les limites de mémoire sur les systèmes x86. Je ne connais pas la longueur finale, je dois donc utiliser un type extensible. Sur les systèmes x64, je peux utiliser .

Mon type de données actuel:

 List param1 = new List(); List param2 = new List(); List param3 = new List(); public class RawData { public ssortingng name; public List data; } 

La longueur des listes de parameters est faible (actuellement de 50 ou moins), mais les données peuvent être supérieures à 10 m. Lorsque la longueur est de 50, OutOfMemoryException limites de mémoire ( OutOfMemoryException ) à un peu plus de 1 m de points de données et lorsque la longueur est de 25, OutOfMemoryException la limite à un peu plus de 2 m de points de données. (Si mes calculs sont exacts, cela correspond exactement à 200 Mo, plus la taille du nom, plus les frais généraux). Que puis-je utiliser pour augmenter cette limite?

Edit: J’ai essayé d’utiliser List<List> avec une taille de liste interne maximale de 1 << 17 (131072), ce qui a légèrement augmenté la limite, mais pas autant que je le voulais.

Edit2: J’ai essayé de réduire la taille du bloc dans la liste> à 8192, et j’ai obtenu du MOO à environ 2,3 m, avec un gestionnaire de tâches lisant environ 1,4 Go pour le processus. Il semble que j’ai besoin de réduire l’utilisation de la mémoire entre la source de données et le stockage, ou de déclencher le CPG plus souvent – j’ai pu rassembler 10 m de points de données dans un processus x64 sur un ordinateur doté de 4 Go de RAM, le processus IIRC n’a jamais dépassé 3 Go.

Edit3: J’ai condensé mon code uniquement sur les parties qui gèrent les données. http://pastebin.com/maYckk84

Edit4: J’ai jeté un œil dans DotMemory et découvert que ma structure de données prenait environ 1 Go avec les parameters testés (50 canaux * 3 parameters * 2m événements = 300 000 000 éléments flottants). Je suppose que je devrai le limiter à x86 ou comprendre comment écrire sur un disque dans ce format au fur et à mesure que je reçois des données

Tout d’abord, sur les systèmes x86, la mémoire est limitée à 2 Go et non à 200 Mo. Je présume que votre problème est beaucoup plus compliqué que cela. Vous avez une fragmentation agressive LOH (Large Object Heap).
CLR utilise différents tas pour les petits et les grands objects. L’object est grand si sa taille est supérieure à 85 000 octets. LOH est une chose très pénible, il n’est pas pressé de ramener la mémoire inutilisée dans le système d’exploitation, et il est très pauvre en défragmentation.
La liste .Net est une implémentation de la structure de données ArrayList, elle stocke les éléments dans un tableau de taille fixe; lorsque le tableau est rempli, un nouveau tableau avec une taille doublée est créé. Cette croissance continue du tableau avec votre quantité de données est un scénario de “famine” pour LOH.
Vous devez donc utiliser une structure de données sur mesure pour répondre à vos besoins. Par exemple, une liste de morceaux, avec chaque morceau est assez petit pour ne pas entrer dans LOH. Voici un petit prototype:

 public class ChunkedList { private readonly List _chunks = new List(); private const int ChunkSize = 8000; private int _count = 0; public void Add(float item) { int chunk = _count / ChunkSize; int ind = _count % ChunkSize; if (ind == 0) { _chunks.Add(new float[ChunkSize]); } _chunks[chunk][ind] = item; _count ++; } public float this[int index] { get { if(index <0 || index >= _count) throw new IndexOutOfRangeException(); int chunk = index / ChunkSize; int ind = index % ChunkSize; return _chunks[chunk][ind]; } set { if(index <0 || index >= _count) throw new IndexOutOfRangeException(); int chunk = index / ChunkSize; int ind = index % ChunkSize; _chunks[chunk][ind] = value; } } //other code you require } 

Avec ChunkSize = 8000, chaque bloc ne prendra que 32 000 octets, il ne sera donc pas entré dans LOH. _chunks n’entreront dans LOH que lorsqu’il y aura environ 16 000 morceaux dans la collection, ce qui représente plus de 128 millions d’éléments en collection (environ 500 Mo).

UPD J’ai effectué des tests de résistance pour l’échantillon ci-dessus. Le système d’exploitation est x64, la plate-forme de solution est x86 ChunkSize est 20000.

Premier:

 var list = new ChunkedList(); for (int i = 0; ; i++) { list.Add(0.1f); } 

OutOfMemoryException est levé à ~ 324 000 000 éléments

Seconde:

 public class RawData { public ssortingng Name; public ChunkedList Data = new ChunkedList(); } var list = new List(); for (int i = 0;; i++) { var raw = new RawData { Name = "Test" + i }; for (int j = 0; j < 20 * 1000 * 1000; j++) { raw.Data.Add(0.1f); } list.Add(raw); } 

OutOfMemoryException est levé à i = 17, j ~ 12 000 000. 17 instances RawData ont été créées avec succès, soit 20 millions de points de données chacune, soit environ 352 millions de points de données.