Une stratégie que je pensais à moi-même alloue 5 mégaoctets de mémoire (ou quel que soit le numéro nécessaire) au démarrage du programme. P>
alors, à n'importe quel point du programme Que pensez-vous de cette stratégie? P>
Et quelles autres stratégies savez-vous? P>
Merci, Boda Cydo. P> MALLOC () CODE> Retours code> NULL code>, vous libérez 5 mégaoctets et appelez
MALLOC () code> à nouveau, ce qui sera réussir et laisser le programme continuer à courir. P>
9 Réponses :
Poignez les échecs MALLOC en sortant gracieusement. Avec des systèmes d'exploitation modernes, des pagesFiles, etc., vous ne devez jamais prévenir de préemption pour une défaillance de la mémoire, il vous suffit de sortir gracieusement. Il est peu probable que vous rencontriez déjà des erreurs de mémoire, sauf si vous avez un problème algorithmique. P>
Aussi, allouant 5 Mo sans raison au démarrage est fou. p>
Tout en allouant 5 Mo sans aucune raison n'est pas une bonne idée, avec un bloc de mémoire réservé utilisable pour aider à cette sortie gracieuse n'est pas une mauvaise idée. MS réserve un petit tampon statique pour une déclaration d'erreur de bas niveau. Cela leur donne un emplacement que User32 peut utiliser pour formater un message et l'afficher à l'utilisateur. À ce stade, la récupération n'est pas une option, mais elle peut aider à identifier et à prévenir la question à l'avenir. Quelque chose de similaire dans la demande pourrait être utile.
"Il est peu probable que vous rencontriez déjà des erreurs de mémoire, à moins que vous n'ayez un problème algorithmique." Cela semble un peu comme "personne n'a besoin de plus de 640k RAM". Si vous travaillez sur une machine 32 bits et que votre processus a besoin de 1 Go de données, vous pouvez facilement rencontrer une situation dans laquelle vous ne pouvez pas allouer 5 Mo en raison de la fragmentation de la mémoire.
Vous pouvez ajouter qu'une partie de la sortie de manière gracieusement devrait veiller à ce que les données sur le disque soient dans un état cohérent (par exemple, si vous étiez au milieu d'un fichier, ou si votre application a une base de données ouverte) et éventuellement écrire un fichier Cela peut être utilisé pour récupérer les données de la session en cours lorsque l'application est redémarrée.
@EvilClown - Je crois que + Nikie + parlait de fragmentation de la liste gratuite du tas, qui peut se produire lorsque vous Malloc et de nombreuses données de la taille arbitraire. Depuis que c utilise des pointeurs, il est très limité dans la manière dont il peut se fusionner l'espace libre. Vous pouvez avoir beaucoup de mémoire libre, tout simplement pas assez pour une allocation contiguë particulière.
Je pense que les algorithmes de mémoire virtuelle moderne de la mémoire virtuelle dissimulent une fragmentation plutôt avec succès. Par exemple, Void * x peut pointer sur 0x400123F0 et être paginé sur le disque. Plus tard, il peut être échangé dans la RAM à l'adresse 0x5383120F, le pointeur étant traduit par le système d'exploitation afin que le programme soit inconscient. Devrait-il ne pas être en mesure d'obtenir un bloc contigu, une nouvelle page peut être créée et le 0x400123F0 indiquera le nouveau bloc contigu de manière transparente. Un problème plus difficile serait de rendre Malloc Retour NULL.
@EvilClown: la fragmentation de la mémoire n'a rien à voir avec la mémoire physique, mais la fragmentation de l'espace d'adresses virtuel B>. Vous ne pouvez pas déplacer des objets à différentes adresses virtuelles, car alors les pointeurs d'eux ne seraient plus valides.
comme méthode de test que vous gérez gracieusement des situations de mémoire, cela peut être une technique raisonnablement utile. P>
Dans toute autre circonstance, cela semble inutile au mieux. Vous causez la situation hors de la mémoire, puis fixant le problème en libérant la mémoire que vous n'aviez pas besoin de commencer avec. P>
Cela dépend en fait d'une politique que vous souhaitez mettre en œuvre, ce qui signifie que le comportement attendu de votre programme lorsqu'il est hors de mémoire. P>
Une grande solution serait d'allouer de la mémoire lors de l'initialisation et ne serait jamais pendant l'exécution. Dans ce cas, vous ne manquerez jamais de mémoire si le programme a réussi à démarrer. P>
Un autre pourrait libérer des ressources lorsque vous appuyez sur la limite de mémoire. Il serait difficile de mettre en œuvre et de tester. P>
Gardez à l'esprit que lorsque vous obtenez Vous devez effectivement vous assurer (par calcul estimé ou en vérifiant la quantité de mémoire en cours d'exécution) que la quantité attendue de la mémoire libre L'ordinateur est suffisant pour votre programme. P> null code> à partir de
masloc code> Cela signifie que la mémoire physique et virtuelle n'a pas plus d'espace libre, ce qui signifie que votre programme échange tout le temps, ralentissant lentement et l'ordinateur ne répond pas. P>
tandis que (MALLOC (10000000)); CODE> Ce programme conduira rapidement à
MALLOC CODE> Échec de l'échec mais ne échange pas du tout, car la majeure partie de l'espace alloué est constitué de références à zéro page, et n'occupe pas de mémoire physique.
Généralement, le but de libérer la mémoire est de l'avoir suffisamment pour signaler l'erreur avant de mettre fin au programme. P>
Si vous allez simplement continuer à courir, il n'est pas question de préallocer la réserve d'urgence. P>
La plupart des systèmes d'OSE modernes en configuration par défaut permettent à la mémoire Overgmit, votre programme ne serait donc pas nul de MALLOC () du tout ou au moins jusqu'à ce qu'il soit en quelque sorte (par erreur, je suppose) épuisé tous les espaces d'adresses disponibles (pas la mémoire) . Et ensuite, il écrit un emplacement de mémoire parfaitement légal, obtient une faute de page, il n'y a pas de page de mémoire dans le magasin de support et à Bang (Sigbus) - vous mort, et il n'y a pas de bon moyen là-bas. P>
Alors, n'oubliez pas, vous ne pouvez pas le gérer. P>
Bien que cela soit généralement vrai, tout bon système d'exploitation peut être configuré pour ne pas surmonter et sera configuré de cette manière pour tout système nécessitant une fiabilité maximale (par exemple tout système en temps réel - voudriez-vous vraiment trop sur votre moniteur de coeur ??).
Seriez-vous vraiment envie de Malloc ()? :)
Ouais, cela ne fonctionne pas dans la pratique. Premièrement pour une raison technique, une implémentation de tas de fragmentation typique ne rend pas de grands blocs libres disponibles pour les petites allocations. P>
Mais le vrai problème est que vous ne savez pas pourquoi em> vous avez manqué d'espace de mémoire virtuelle. Et si vous ne savez pas pourquoi, alors il n'y a rien que vous puissiez faire pour empêcher que la mémoire supplémentaire d'être consommée très rapidement et toujours em> écrase votre programme avec OOM. Ce qui est très susceptible de se produire, vous avez déjà consommé près de deux gigaoctets, que 5 Mo supplémentaires est une goutte d'eau sur une plaque chauffante. P>
Tout type de schéma qui utilise l'application en «mode d'urgence» est très pratique. Vous devrez abandonner le code d'exécution afin que vous puissiez arrêter, disons, charger un énorme fichier de données. Cela nécessite une exception. Maintenant que vous êtes de retour à ce que vous avez déjà eu avant, STD :: BADALLOC. P>
Êtes-vous sûr du premier paragraphe? Je m'attendrais à ce qu'une bonne implémentation MALLOC d'essayer toutes les manières possibles de satisfaire la demande avant de renvoyer l'échec. Il serait assez ridicule pour malloc (1) code> échouer mais
malloc (100000) code> pour réussir ... Si rien d'autre,
malloc code> pourrait simplement
Ouais, rien de bon ne se passe quand il fragment le tas, essayant de retarder l'inévitable. Ensuite, laisse l'application avec un gâchis qui est très i> difficile à récupérer.
"Essayez-la-nouveau-plus tard". Juste parce que vous êtes OOM maintenant, cela ne signifie pas que vous serez plus tard lorsque le système est moins occupé.
void *smalloc(size_t size) { for(int i = 0; i < 100; i++) { void *p = malloc(size); if(p) return p; sleep(1); } return NULL; }
Le succès ou l'échec de MALLOC a généralement plus à voir avec l'espace d'adressage du processus actuel qu'avec l'état de la machine. Dans la plupart des cas, votre boucle sera infinie. Et je doute que quiconque appréciera la demande de congélation totalement plutôt que de quitter et (espérons-le) enregistrer des données de récupération.
Cela dépend beaucoup de votre système (par exemple, un périphérique Linux intégré sans swap et OverCommit désactivé est différent d'une station de travail Windows 7). Et par exemple tandis qu'un thread est éteint de travailler lourd, vous pourriez être temporaire de la mémoire / de l'espace d'adressage. Toutes les applications ne sont pas supervisées par l'utilisateur - il n'ya donc aucun utilisateur d'ennuyer par "gèle" périodiquement.
Au cours des dernières années, le logiciel (intégré) que j'ai travaillé avec généralement ne permet pas l'utilisation de MALLOC (). La seule exception à cet égard est qu'elle est autorisée pendant la phase d'initialisation, mais une fois que cela est décidé que plus d'allocations de mémoire ne sont autorisées, tous les appels futurs à Malloc () échouent. Comme la mémoire peut devenir fragmentée en raison d'un MALLOC () / gratuit (), il devient difficile au mieux dans de nombreux cas de prouver que les appels futurs à Malloc () ne manqueront pas. P>
Un tel scénario pourrait ne pas s'appliquer à votre cas. Cependant, sachant pourquoi Malloc () échoue peut être utile. La technique suivante que nous utilisons dans notre code puisque MALLOC () n'est généralement pas disponible (ou pourrait ne pas) être applicable à votre scénario. P>
Nous avons tendance à compter sur des pools de mémoire. La mémoire de chaque pool est allouée pendant la phase de démarrage transitoire. Une fois que nous avons les piscines, nous obtenons une entrée de la piscine lorsque nous en avons besoin et la relâchez-la à la piscine lorsque nous sommes terminés. Chaque piscine est configurable et est généralement réservée à un type d'objet particulier. Nous pouvons suivre l'utilisation de chaque fois. Si nous manquons d'entrées de piscine, nous pouvons découvrir pourquoi. Si nous ne le faisons pas, nous avons la possibilité de rendre notre piscine plus petite et de gagner des ressources. P>
J'espère que cela aide. P>
+1 pour couvrir le seul moyen d'écrire des applications vraiment robustes.
Une approche utile d'allocation de mémoire dans les systèmes intégrées est la LIFO Alloc / Gratuit; libérer un pointeur renvoyé par une allocation retourne cette mémoire et tout alloué par la suite i>. Si son tas est préalablement alloué (plutôt que de partager la mémoire avec la pile), il peut être facilement adapté pour allouer la mémoire du haut et du bas, offrant deux allocateurs LIFO pour le même pool partagé.
Je veux seconder le sentiment que l'approche de pré-allocation de 5 Mo est "folle", mais pour une autre raison: elle est soumise à des conditions de course. Si la cause de l'épuisement de la mémoire est dans votre programme (espace d'adressage virtuel épuisé), un autre thread pourrait réclamer les 5 Mo après votre liberté, mais avant de pouvoir l'utiliser. Si la cause de l'épuisement de la mémoire est le manque de ressources physiques sur la machine en raison d'autres processus utilisant trop de mémoire, ces autres processus pourraient réclamer les 5 Mo après votre liberté (si la mise en œuvre MALLOC renvoie l'espace au système). P >
Certaines applications, comme une musique ou un lecteur de cinéma, seraient parfaitement justifiées simplement en sortant des défaillances d'allocation - ils gèrent peu de données modifiables. D'autre part, je pense que toute application utilisée pour modifier les données potentiellement précieuses doit avoir un moyen de (1) garantir que les données déjà sur le disque sont laissées dans un état cohérent et non corrompu, et (2) écrit. Un journal de récupération de quelque sorte de sorte que, sur des invocations ultérieures, l'utilisateur puisse récupérer les données perdues lorsque l'application a été forcée de fermer. P>
Comme nous l'avons vu dans le premier paragraphe, en raison des conditions de course, votre approche "MALLOC 5MB et IT" ne fonctionne pas. Idéalement, le code pour synchroniser des informations de récupération de données et d'écriture serait totalement exempt d'attribution; Si votre programme est bien conçu, il est probablement naturellement exempt d'attribution. Une approche possible Si vous savez que vous aurez besoin d'allocations à ce stade consiste à mettre en œuvre votre propre allocator qui fonctionne dans un petit tampon / piscine statique et utilisez-le pendant l'arrêt de l'échec de l'allocation. P>
Accepter. Je peux voir une certaine utilité pour pré-allouer les 5 Mo si on peut utiliser la mémoire directement (sans avoir à le relâcher en premier) et si 5 Mo est la quantité réelle de données qui seront nécessaires pour un arrêt sûr. Cela ne sonne pas comme le cas ici.
Et que gagnez-vous de faire cela? Vous pouvez mettre en œuvre une "mémoire libre supplémentaire lorsque l'OMM est détectée" la logique qui aurait pu être évitée.