45 votes

Quelle est la manière élégante de gérer des situations de mémoire insuffisante en C / C ++?

Je suis en train d'écrire un cache d'application qui consomme de grandes quantités de mémoire.

Je l'espère, je vais gérer ma mémoire assez bien, mais je suis juste à penser à ce à faire si je n'ai manquer de mémoire.

Si un appel à allouer même un simple objet échoue, il est probable que même un appel syslog sera également échouer?

EDIT: Ok j'ai peut-être devrait clarifier la question. Si la fonction malloc ou de nouveaux renvoie une valeur NULL ou 0L valeur alors il signifie, en substance, l'appel a échoué et il ne peut pas vous donner la mémoire pour une raison quelconque. Donc, ce serait la chose la plus sensée à faire dans ce cas?

EDIT2: je viens de réalisé qu'un appel à la "nouvelle" peut lever une exception. Cela pourrait être pris à un niveau plus élevé, donc je peux peut-être arrêter normalement plus haut. À ce stade, il peut même être possible de récupérer en fonction de combien de mémoire est libérée. Au moins je dois par ce point, nous l'espérons être en mesure de se connecter à quelque chose. Ainsi, alors que j'ai vu du code qui vérifie la valeur d'un pointeur, après la nouvelle, il n'est pas nécessaire. Alors qu'en C, vous devez vérifier la valeur de retour de malloc.

18voto

Billy ONeal Points 50631

Eh bien, si vous êtes dans un cas où il y a un échec d'allocation de mémoire, vous allez obtenir un std::bad_alloc d'exception. L'exception des causes de la pile de votre programme à être déroulé. Selon toute vraisemblance, à l'intérieur des boucles de la logique de l'application ne sont pas va être de la manipulation de la mémoire, seuls les niveaux supérieurs de votre demande doit être faire cela. Parce que la pile est d'obtenir déroulés, d'une importante partie de la mémoire va être libre serais-ce qui, en fait, devrait être la quasi-totalité de la mémoire utilisée par votre programme.

La seule exception à cette règle est lorsque vous demandez un très grand (plusieurs centaines de MO, par exemple) partie de la mémoire qui ne peut pas être satisfait. Lorsque cela arrive, cependant, il y a généralement assez de petits morceaux de mémoire restante qui vous permettra de gérer harmonieusement l'échec.

Le déroulement de pile est votre ami ;)

EDIT: Viens de réaliser que la question a également été marqués avec le C -- si c'est le cas, alors vous devriez avoir votre fonctions libres de leurs structures internes manuellement lors de la sortie de la mémoire de conditions; ne pas le faire est une fuite de mémoire.

EDIT2: Exemple:

#include <iostream>
#include <vector>

void DoStuff()
{
    std::vector<int> data;
    //insert a whole crapload of stuff into data here.
    //Assume std::vector::push_back does the actual throwing
    //i.e. data.resize(SOME_LARGE_VALUE_HERE);
}

int main()
{
    try
    {
        DoStuff();
        return 0;
    }
    catch (const std::bad_alloc& ex)
    {   //Observe that the local variable `data` no longer exists here.
        std::cerr << "Oops. Looks like you need to use a 64 bit system (or "
                     "get a bigger hard disk) for that calculation!";
        return -1;
    }
}

EDIT3: Bon, selon les commentateurs il y a des systèmes qui ne suivent pas la norme dans ce domaine. D'autre part, sur de tels systèmes, vous allez être de SOL dans tous les cas, donc je ne vois pas pourquoi ils méritent d'être discutés. Mais si vous êtes sur une plate-forme, c'est quelque chose à garder à l'esprit.

18voto

Arafangion Points 5650

Cette question ne fait-elle pas l'hypothèse d'une mémoire surchargée?

C'est-à-dire qu'une situation de mémoire insuffisante pourrait ne pas être récupérable! Même s'il ne vous reste plus de mémoire, les appels à malloc et à d'autres allocateurs peuvent continuer jusqu'à ce que le programme tente d'utiliser la mémoire. Alors, BAM! , certains processus sont tués par le noyau afin de satisfaire la charge de la mémoire.

4voto

gavinb Points 9237

Si votre demande est susceptible d'allouer de gros blocs de mémoire et risque de heurter la par processus ou VM limites, en attente jusqu'à ce qu'une répartition en fait échec est une situation difficile pour les récupérer. Par les temps malloc retours NULL ou new jette std::bad_alloc, les choses peuvent être allée trop loin pour une récupération fiable. En fonction de votre stratégie de récupération, de nombreuses opérations peuvent nécessiter encore les allocations de segments eux-mêmes, de sorte que vous devez être extrêmement prudent sur les routines qui vous pouvez compter.

Une autre stratégie, vous pouvez envisager une requête à l'OS et surveiller la mémoire disponible, la gestion proactive de vos allocations. De cette façon, vous pouvez éviter d'allouer un bloc de taille importante si vous savez qu'il est susceptible d'échouer, et aura donc une meilleure chance de guérison.

Aussi, en fonction de votre utilisation de la mémoire de motifs, à l'aide d'un allocateur personnalisé peut vous donner de meilleurs résultats que la norme intégrée malloc. Par exemple, certains modèles d'allocation peut effectivement conduire à une fragmentation de la mémoire au fil du temps, de sorte que même si vous avez de la mémoire libre, les blocs disponibles dans le tas arena ne peut pas avoir un bloc disponible de la taille. Un bon exemple est celui de Firefox, qui a basculé en dmalloc et a vu une grande augmentation de l'efficacité de mémoire.

2voto

Jens Gustedt Points 40410

Je ne pense pas que la capture de l'échec de l' malloc ou new gagnerez vous avez beaucoup dans votre situation. linux alloue de gros morceaux de virtuel pages en malloc par mmap. Par cela, vous pouvez vous trouver dans une situation où vous allouer beaucoup plus de mémoire virtuelle que vous avez (réel + swap).

Ensuite, le programme échoue seulement beaucoup plus tard avec une erreur de segmentation (SIGSEGV) lorsque vous écrivez à la première page pour laquelle il n'y a pas de n'importe quel endroit dans le swap. En théorie, vous pourriez tester ces situations par l'écriture d'un gestionnaire de signal, puis salir toutes les pages que vous allouer.

Mais souvent, cela n'aide pas beaucoup non plus, depuis que votre application sera dans un très mauvais état à long avant qu': toujours à la permutation, l'informatique, la mécanique avec votre disque dur...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X