Question

Question dit tout, mais voici un exemple:

typedef struct mutable_t{
    int count, max;
    void **data;
} mutable_t;


void pushMutable(mutable_t *m, void *object)
{
    if(m->count == m->max){
        m->max *= 2;
        m->data = realloc(m->data, m->max * sizeof(void*));
    }
    // how to handle oom??
    m->data[m->count++] = object;
}

Comment puis-je gérer à court de mémoire et non NULL à toutes mes données?

modifier - supposons qu'il ya quelque chose qui pourrait être fait par exemple libérer de la mémoire quelque part ou au moins indiquer à l'utilisateur « vous ne pouvez pas faire cela - vous êtes hors de la mémoire ». Idéalement, je voudrais laisser ce qui a été attribué il.

Était-ce utile?

La solution

La technique standard est d'introduire une nouvelle variable pour tenir le retour de realloc. Ensuite, vous écrasez votre seule variable d'entrée si elle réussit:

tmp = realloc(orig, newsize);
if (tmp == NULL)
{
    // could not realloc, but orig still valid
}
else
{
    orig = tmp;
}

Autres conseils

La stratégie sur ce qu'il faut faire en cas d'échec realloc() dépend de votre application. La question est trop générique pour répondre à tous les cas possibles.

D'autres notes:

Ne jamais faire:

a = realloc(a, size);

En cas d'échec realloc(), vous perdez le pointeur d'origine, et ne realloc() free() pas la mémoire d'origine, vous obtiendrez une fuite de mémoire. Au lieu de cela, faites:

tmp = realloc(a, size);
if (tmp)
    a = tmp;
else
    /* handle error */

Deuxième point que je veux faire est mineur et ne peut pas être que critique, mais il est bon de savoir à ce sujet de toute façon: augmenter la mémoire à allouer par un facteur f est bon. Disons que vous malloc() n octets d'abord. Ensuite, vous avez besoin de plus de mémoire, de sorte que vous realloc() avec la taille n × f . Ensuite, vous avez besoin de plus de mémoire, vous avez donc besoin n × f 2 octets. Si vous voulez realloc() utiliser l'espace des deux blocs de mémoire précédents, vous voulez vous assurer que n × f 2 ≤ n + n × f . La résolution de cette équation, nous obtenons f ≤ (sqrt (5) + 1) / 2 = 1,618 ( rapport d'or ). J'utilise un facteur de 1.5 la plupart du temps.

Ceci est un peu un sujet de bouton chaud comme il y a essentiellement 2 écoles de pensée sur le sujet

  1. Détecter le MOO, et ayant la fonction retourne un code d'erreur.
  2. Détecter les OOM et planter votre processus aussi vite que possible

Personnellement, je suis dans le camp # 2. Attendez-vous à des types très spéciaux d'applications, OOM est fatale période. Certes, le code parfaitement écrit peut gérer un OOM, mais si peu de gens comprennent comment écrire du code qui est sûr en face d'une mémoire. Encore moins la peine de le faire réellement, car il est presque jamais en vaut la peine.

Je n'aime passer le code d'erreur de la fonction d'appel pour de OOM, car il est l'équivalent de dire l'appelant «J'échoué et il n'y a rien que vous pouvez faire à ce sujet ». Au lieu de cela, je préfère tomber en panne rapide de sorte que le fichier de sauvegarde résultant est aussi instructif que possible.

La première règle que vous shoud suivre lorsque vous travaillez avec realloc est de ne pas affecter la valeur de retour de realloc au même pointeur que vous a été transmis. Ce

m->data = realloc(m->data, m->max * sizeof(void*)); 

est mauvais. Si realloc échoue, il renvoie un pointeur NULL, mais il ne désallouer pas la vieille mémoire. Le code ci-dessus null votre m->data tandis que l'ancien bloc de mémoire pointé précédemment par m->data sera très probablement devenir fuite de mémoire (si vous avez pas d'autres références à elle).

La valeur de retour de realloc doit être stocké dans un pointeur séparé premier

void **new_data;
...
new_data = realloc(m->data, m->max * sizeof(void*)); 

Ensuite, vous pouvez vérifier le succès / échec et changer la valeur de m->data en cas de succès

if (new_data != NULL)
  m->data = new_data;
else
  /* whatever */;

C'est tout à fait votre problème! Voici quelques critères:

  • Vous avez demandé que la mémoire pour une raison. Si ce n'est pas disponible, est le travail de votre programme condamné ou peut-il continuer à faire des choses? Si l'ancien, vous voulez mettre fin à votre programme avec un message d'erreur; sinon, vous pouvez afficher un message d'erreur en quelque sorte et continuer.

  • Est-il possible d'échanger du temps pour l'espace? Pourriez-vous répondre tout opération que vous tentez en utilisant un algorithme qui utilise moins de mémoire? Cela ressemble à beaucoup de travail, mais serait en effet une possibilité de poursuivre le fonctionnement de votre programme en dépit de ne pas avoir assez de mémoire au départ.

  • Serait-il faux de votre programme de continuer boitant sans ces données et pas assez de mémoire? Si oui, vous devez terminer avec un message d'erreur. Il est préférable de tuer votre programme que de continuer aveuglément traitement des données incorrectes.

  1. Découvrez comment le cadre de l'application gère un OOM. Beaucoup tout simplement pas gérer un OOM. La plupart du temps un cadre ne fonctionne pas correctement en aucun sans-RAM conditions moins qu'il indique très clairement et sans ambiguïté quelque part que ce sera. Si le cadre ne traitera pas un OOM et multithread (beaucoup sont de nos jours), un OOM va être la fin du spectacle pour le processus dans beaucoup de cas. Même si elle n'est pas multithread il peut encore être proche de l'effondrement. Si vous quittez le processus ou le cadre ne peut être un point discutable; une sortie immédiate prévisible peut être juste un peu mieux que d'un accident à un moment donné semi-aléatoire dans un proche avenir.

  2. Si vous utilisez une piscine séparée à usage spécial sous-mémoire (c.-à-pas votre habitude malloc) pour un ensemble bien défini des opérations qui ne sont contraintes dans l'utilisation de la mémoire par OOM (à savoir l'opération en cours est annulée ou interrompue proprement sur OOM pour la piscine sous-mémoire, et non pas l'ensemble du processus ou principal pool de mémoire), et que la sous-piscine n'est pas également utilisé par le cadre d'application, ou si votre cadre et l'ensemble du reste du application est conçue pour maintenir l'état significatif et le fonctionnement continu en aucun sans-RAM conditions (rare mais pas rare en mode noyau et certains types de programmation de systèmes), vous pouvez être droit de retourner un code d'erreur plutôt que de bloquer le processus.

  3. Idéalement, la majeure partie des allocations de mémoire (ou encore plus idéalement tous les allocations) pour un morceau de traitement devrait être alloué le plus tôt possible dans le traitement, idéalement avant qu'il ne commence correctement, de minimiser les problèmes de perte d'intégrité des données et / ou la quantité de rollback codage requis si elle échoue. Dans la pratique, beaucoup de temps, pour réduire les coûts de la programmation et le temps des projets, pour préserver les applications d'intégrité des données reposent sur les transactions de base de données et nécessitant la personne utilisateur / support pour détecter un accident d'interface utilisateur graphique (ou plantage du serveur) et redémarrez l'application lorsque de erreurs de mémoire se produisent, plutôt que d'être écrit pour faire face et rollback sur tout et tous des milliers de situations potentielles de OOM dans les meilleures façons possibles. Ensuite, les efforts se concentrent à essayer de limiter l'exposition de l'application à des situations de surcharge, ce qui peut inclure une validation supplémentaire et des limites sur la taille des données et connexions simultanées et des requêtes.

  4. Même si vous vérifiez la quantité de mémoire est signalée code disponible, souvent autre peut alloc ou la mémoire libre comme vous le faites, en changeant la base de votre vérification de la mémoire et qui peut conduire à OOM. Donc, la vérification RAM disponible avant alloc est souvent une solution fiable au problème de vous assurer que votre application fonctionne dans les limites de la RAM disponible et maintient suffisamment l'intégrité des données du temps pour satisfaire les utilisateurs.

  5. La meilleure situation en est de savoir combien de mémoire votre application nécessite dans tous les cas possibles, y compris les frais généraux cadres, et de garder ce chiffre au sein de la quantité de RAM disponible pour votre application, mais les systèmes sont souvent si compliqué avec des dépendances externes dictant la taille des données afin cela peut être atteint irréaliste.

Le test acide est bien sûr vous satisfaire sont les utilisateurs suffisamment haut par temps, et les données peu fréquentes corruption, la perte ou les accidents. Dans certains cas, une application ayant un processus de surveillance pour le redémarrer si elle tombe en panne est utile.

En ce qui concerne realloc:

Vérifier la valeur de retour de realloc - le mettre dans une variable temporaire. soins que si elle est NULL si la nouvelle taille demandée était> 0. Dans d'autres cas placer dans votre variable non temporaire:

par exemple

    void* temp = realloc(m->data, m->max * sizeof(void*));
    if (m->max!=0&&temp==NULL) { /* crash or return error */ }
    m->data =(void**)temp;

EDIT

Changé "la plupart des cas" à "beaucoup de cas" dans (1).

Je reconnais que vous avez dit de supposer que « quelque chose peut être fait » si la mémoire ne peut être attribuée. Mais la gestion de la mémoire est une considération très globale (!).

Il y a aussi une autre erreur subtile qui peut venir de realloc. La fuite de mémoire provenant de pointeur NULL retournée est assez bien connu (mais tout à fait rare de tomber par hasard sur). J'ai eu dans mon programme un accident de temps en temps qui est venu d'un appel de realloc. J'ai eu une structure dynamique qui ajuste automatiquement sa taille avec un realloc ressemblant à celui-ci:

m->data = realloc(m->data, m->max * sizeof(void*)); 

L'erreur que fait était de ne pas vérifier m-> max == 0, ce qui libère la zone de mémoire. Et fait de mon M-> données pointer un rassis.

Je sais qu'il est un peu hors sujet, mais ce fut la seule vraie question que j'ai jamais eu avec realloc.

Je suis venu dans la configuration problème.Le est OS: Win7 (64); IDE: vs2013; Debug (Win32)
. Quand mon realloc est revenu nulle en raison de la mémoire ont in.I deux solutions à cela:

1.Changer la propriété du projet, pour permettre ADRESSES LARGE.
2.Modifiez ma plate-forme de solution de Win32 x64.

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