Comment éviter de manquer de mémoire dans l'application d'une utilisation élevée de la mémoire? C / C ++

StackOverflow https://stackoverflow.com/questions/741834

  •  09-09-2019
  •  | 
  •  

Question

Je l'ai écrit un convertisseur qui prend les fichiers OpenStreetMap xml et les convertit en un format de rendu d'exécution binaire qui est généralement d'environ 10% de la taille originale. la taille des fichiers d'entrée sont généralement 3Go et plus. Les fichiers d'entrée ne sont pas chargés dans la mémoire à la fois, mais ruisselaient comme points et polys sont collectés, puis un bsp est exécuté sur eux et le fichier est sortie. Récemment sur des fichiers plus volumineux, il est à court de mémoire et meurt (celui en question a 14 millions de points et 1 million de polygones). En règle générale mon programme utilise environ 1 Go à 1,2 Go de RAM lorsque cela se produit. J'ai essayé d'augmenter la mémoire virtuelle de 2 à 8gb (sur XP), mais ce changement fait aucun effet. En outre, étant donné que ce code est open source, je voudrais le faire fonctionner quel que soit le RAM disponible (mais plus lent), il fonctionne sous Windows, Linux et Mac.

Quelles techniques puis-je utiliser pour éviter d'avoir couler de mémoire? Le traitement des données en sous-ensembles plus petits, puis fusionner les résultats finaux? En utilisant mon propre type de mémoire virtuelle de gestionnaire? D'autres idées?

Était-ce utile?

La solution

Tout d'abord, sur un système 32 bits, vous serez toujours limité à 4 Go de mémoire, peu importe les paramètres pagefile. (Et ceux-ci, seulement 2 Go sera disponible pour votre processus sous Windows. Sur Linux, vous aurez généralement autour de 3 Go disponibles)

La première solution évidente est de passer à un système d'exploitation 64 bits, et compiler votre application 64 bits. Cela vous donne un énorme espace de mémoire virtuelle à utiliser, et le système d'exploitation et échanger des données sur le fichier d'échange que nécessaire pour continuer à travailler les choses.

En second lieu, l'allocation de petits morceaux mémoire à la fois peut aider. Il est souvent plus facile de trouver 4 morceaux de 256 Mo de mémoire libre d'un morceau de 1 Go.

Troisièmement, diviser le problème. Ne pas traiter l'ensemble de ces données à la fois, mais essayez de charger et traiter seulement une petite section à la fois.

Autres conseils

Avez-vous vérifié pour vous assurer de ne pas une fuite de mémoire nulle part?

Étant donné que votre programme est portable à Linux, je vous suggère de faire fonctionner sous Valgrind pour vous assurer.

On dirait que vous faites déjà un SAX approche basée sur le traitement XML ( le chargement du XML que vous allez au lieu de tout à la fois).

La solution est presque toujours de changer l'algorithme afin qu'il coupe le problème en parties plus petites. Physiquement ne pas allouer autant de mémoire à un moment donné, lisez dans seulement ce dont vous avez besoin, processus, puis l'écrire.

Vous pouvez parfois étendre la mémoire via le disque dur en utilisant la place en cas de besoin dans votre algorithme.

Si vous ne pouvez pas diviser votre algorithme, vous voulez probablement quelque chose comme mémoire des fichiers mis en correspondance .

Dans le pire des cas, vous pouvez essayer d'utiliser quelque chose comme VirtualAlloc si vous êtes sur un système de fenêtres. Si vous êtes sur un système 32 bits, vous pouvez essayer d'utiliser quelque chose comme Extension d'adresse physique (PAE) .

Vous pouvez également envisager de mettre des limites d'entrée pour votre programme, et ayant une autre pour 32 bits et 64 bits.

Je soupçonne que vos problèmes de mémoire sont de garder l'arbre BSP en mémoire. Alors gardez le BSP sur le disque et ne garder que certains morceaux en mémoire. Cela devrait être assez facile avec BSP, la structure se prête plus que d'autres structures d'arbres, et la logique doit être simple. Pour être à la fois efficace et conviviale mémoire que vous pourriez avoir un cache w / drapeau sale, avec la taille du cache mis à la mémoire disponible moins un peu pour la salle de respiration.

32 bits XP espace d'adressage de programme maximum est de 2 Go. Ensuite, vous avez la fragmentation en raison de DLL et chargement des pilotes dans votre espace d'adressage. Enfin, vous avez le problème de votre fragmente en tas.

Votre meilleur coup est juste pour en finir et exécuter un processus 64 bits (sur un système 64 bits). Tout à coup, tous ces problèmes disparaissent. Vous pouvez utiliser un meilleur tas pour atténuer les effets de la fragmentation du tas, et vous pouvez essayer d'utiliser VirtualAlloc pour saisir votre mémoire dans un seul gros morceau contigu (et puis vous arrivez à le gérer à partir de là!) Pour décourager les conducteurs de DLL / de fragmenter.

Enfin, vous pouvez diviser votre BSP dans tous les processus. Compliqué et douloureux, et franchement juste le mettre sur le disque serait plus facile, mais en théorie, vous pourriez obtenir de meilleures performances en ayant un groupe de processus échange d'informations, si vous pouvez garder tout résident (et en supposant que vous pouvez être plus intelligent que la mémoire que le système d'exploitation peut gérer en mémoire tampon des fichiers ... qui est un grand si). Chaque processus aurait besoin de beaucoup moins de mémoire et ne devrait donc pas courir dans la limite de l'espace d'adressage de 2 Go. Bien sûr, vous brûlerez par RAM / échanger beaucoup plus vite.

Vous pouvez atténuer les effets de la fragmentation de l'espace d'adressage en allouant des morceaux plus petits. Cela aura d'autres effets secondaires désagréables, mais vous pouvez suivre une politique de backoff où vous prenez plus en plus petits morceaux de mémoire si vous ne parvenez pas à attribuer avec succès. Fréquemment, cette approche simple vous obtiendrez un programme qui fonctionne quand il ne serait pas autrement, mais le reste du temps fonctionne aussi bien qu'il le pourrait.

Boy, n'a pas 64 bits du son juste tellement plus agréable que les autres choix?

Comment répartissez-vous la mémoire pour les points? Allouez-vous un point à un moment (par exemple pt = new Point). Ensuite, en fonction de la taille du point, de la mémoire peut se défoncent. Par exemple sur la mémoire Windows est allouée dans les multiples de 16 octets, même si vous demandez essayez d'allouer 1 octet, OS sera effectivement allouer 16 octets.

Si tel est le cas, en utilisant un allocateur de mémoire peut aider. Vous pouvez faire une vérification rapide en utilisant STL allocateur. (Plus de charger le nouvel opérateur pour la classe Point et utiliser l'allocateur STL pour allouer de la mémoire plutôt que « malloc » ou par défaut nouvel opérateur).

Vous ne pouvez pas allouerons et désaffecter la mémoire de manière optimale. Comme d'autres l'ont souligné, vous pouvez être une fuite de mémoire et sans le savoir. Mise au point et l'optimisation de l'allocation de mémoire prendra du temps.

Si vous ne voulez pas passer du temps à optimiser l'utilisation de la mémoire, pourquoi ne pas essayer le Garbage Collector conservateur ? Il est un remplacement pour malloc plug-in () / nouvelle et libre (). En fait, libre () est un non-op, vous pouvez simplement supprimer ces appels de votre programme. Si, au contraire, vous la main d'optimiser votre programme et gérer un pool de mémoire comme suggéré précédemment, vous finirez par faire beaucoup de travail que la CCG fait déjà pour vous.

Vous devez diffuser votre sortie ainsi que votre entrée. Si votre SOCK_STREAM format de sortie n'est pas, envisager de faire la deuxième passe. Par exemple, si le fichier de sortie commence par checksum / taille des données, laissez l'espace sur la première passe et recherche / écriture à cet espace plus tard.

Il dirait que vous faites txt à la conversation binaire alors pourquoi avez-vous besoin d'avoir toutes les données dans la mémoire ?.
Tu ne peux pas lire juste une primitive de txt (xml) puis enregistrez à BinaryStream?

Si vous voulez être la taille de la mémoire indépendante, vous avez besoin d'un algorithme de taille indépendante. Peu importe la taille de votre RAM est, si vous ne disposez pas utilisation de la mémoire sous contrôle, vous allez tomber sur la frontière.

Jetez un oeil à la moindre partie de l'information que vous pouvez éventuellement utiliser pour produire un peu de la production. Alors pensez à un moyen de diviser l'entrée en morceaux de cette taille.

Maintenant, cela semble facile, non? (Je suis content de ne pas avoir à le faire :))

Vous n'avez pas besoin de passer à des machines 64 bits, ni vous avez besoin la plupart des 1000 choses suggérées par d'autres. Qu'est-ce que vous avez besoin est un algorithme plus réfléchi.

Voici quelques choses que vous pouvez faire pour aider à cette situation:

  • Si vous êtes sous Windows, utilisez Maps fichier ( un exemple de code ). Cela vous donnera accès au fichier via un seul pointeur tampon comme si vous lisez le fichier entier en mémoire, mais sans réellement faire cela. Les versions récentes de Linux noyau ont un mécanisme similaire.
  • Si vous le pouvez, et il semble que vous pouvez, analyser le fichier de manière séquentielle et éviter la création d'un DOM en mémoire. Cela réduira considérablement votre charge en temps ainsi que les exigences de mémoire.
  • Utiliser la mémoire Pooled! Vous aurez probablement beaucoup de petits objets, tels que les nœuds, les points et ainsi de suite. Utilisez une mémoire mis en commun pour aider (je suppose que vous utilisez une langue non gérée. Recherche d'allocation Pooled et pools de mémoire).
  • Si vous utilisez une langue gérée, au moins déplacer cette partie dans une langue non gérée et prendre le contrôle de la lecture de la mémoire et le fichier. langues gérées ont une surcharge non négligeable à la fois l'empreinte mémoire et de performance. (Oui, je sais que cela est marqué "C ++" ...)
  • Tenter de concevoir un, où vous ne lisez et processus algorithme en place la quantité minimum de données à la fois, afin que vos besoins en mémoire baisseraient.

Enfin, permettez-moi de souligner que les tâches complexes exigent des mesures complexes. Si vous pensez que vous pouvez vous permettre une machine 64 bits avec 8 Go de RAM, puis il suffit d'utiliser « fichier lu dans la mémoire, les données de processus, écrire la sortie » algorithme, même si cela prend un jour pour terminer.

il y a une bonne technique pour cela, est de stocker certains cas dans des fichiers, et après les avoir quand vous avez besoin de les utiliser.

cette technique est utilisée par de nombreux logiciels open source comme Doxygen pour être évolutive quand une grande quantité de mémoire est nécessaire.

Ceci est une vieille question, mais, depuis que je l'ai récemment fait la même chose ....

Il n'y a pas de réponse simple. Dans un monde idéal, vous devriez utiliser une machine avec un énorme espace d'adressage (soit 64 bits), et des quantités massives de mémoire physique. l'espace d'adressage énorme ne suffit pas ou il vous reste plus qu'à thrash. Dans ce cas, analyser le fichier XML dans une base de données et des requêtes appropriées, tirez ce dont vous avez besoin. Tout à fait probable que ce soit ce que l'OSM se fait (je crois que le monde est sur le point 330GB).

En réalité, je suis toujours en utilisant XP 32 bits pour des raisons d'opportunité.

Il est un compromis entre l'espace et la vitesse. Vous pouvez faire à peu près tout dans une quantité de mémoire à condition que vous ne se soucient pas combien de temps il faut. L'utilisation des structures de STL vous pouvez analyser tout ce que vous voulez, mais vous tomberez bientôt de mémoire. Vous pouvez définir vos propres allocataires qui échangent, mais encore une fois, ce sera inefficace parce que les cartes, vecteurs, ensembles etc ne savent pas vraiment ce que vous faites.

La seule manière que je trouvais pour faire fonctionner le tout dans un faible encombrement sur une machine 32 bits était de bien réfléchir à ce que je faisais et ce qui était nécessaire quand et briser la tâche en morceaux. efficace mémoire (utilise jamais plus de ~ 100 Mo), mais pas massivement rapide, mais il n'a pas d'importance - comment peut-on souvent ont pour analyser les données XML

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top