9
votes

Est-ce que REALLOC () est-il sûr dans un système embarqué?

Tout en développant un logiciel pour système intégré, j'ai utilisé realloc () fonction plusieurs fois. Maintenant, on m'a dit que je "ne devrait pas utiliser realloc () dans intégré" sans aucune explication.

est realloc () dangereux pour le système embarqué et pourquoi?


6 commentaires

Pourquoi ne demandez-vous pas quiconque vous l'a dit?


Embedded est une zone très très large ces jours-ci.


@CNICUTAR Si je pouvais leur demander alors je ne demanderai jamais cela ici .. !!


@ M.32 J'impliquais que vous ne devriez pas accepter des opinions sans arguments.


@CNICUTAR YA De cette façon, vous avez raison. J'ai discuté avec eux, mais ils viennent de dire que realloc est dangereux d'être incorporé alors n'utilisez donc pas le développeur que je dois donc les suivre ..!


Spécifiquement realloc () et non masloc () ou alloca () ? Je pense que je me souviens que je me souviens de voir realloc () critiqué dans un livre en raison de son comportement très surchargé, une fois, mais je ne vais pas vraiment y aller avec cela, et je serais déçu si quelqu'un ait été apaisé à interdisez-le sur ces motifs.


6 Réponses :


5
votes

Cela dépend du système intégré particulier. La gestion de la mémoire dynamique sur un petit système intégré est délicate pour commencer, mais realloc n'est plus compliqué qu'un gratuit et malloc (bien sûr, Ce n'est pas ce que ça fait). Sur certains systèmes embarqués, vous ne rêverez jamais d'appeler malloc en premier lieu. Sur d'autres systèmes embarqués, vous prétendez presque que c'est un bureau.

Si votre système intégré a un faible allocateur ou pas beaucoup de RAM, alors realloc pourrait provoquer des problèmes de fragmentation. C'est pourquoi vous évitez malloc aussi, car cela provoque les mêmes problèmes.

L'autre raison est que certains systèmes embarqués doivent être une fiabilité élevée et malloc / realloc peut retourner null . Dans ces situations, toute la mémoire est allouée statiquement.


2 commentaires

Je ne suis pas un gars intégré, mais vous semblez aller sur des tangentes sur le libre et le malloc. Realloc est potentiellement beaucoup plus que cela, c'est juste que l'interface est simple.


Je disais que ce n'était pas plus compliqué que Malloc et gratuit, pas que c'était en quelque sorte composé d'eux. Je suis désolé si mon libellé imprécis mérite votre désapprobation.



21
votes

Oui, toute une allocation de mémoire dynamique est considérée comme dangereuse et elle est interdite de la plupart des systèmes intégrés «d'intégrité élevée», tels que Industriel / Automobile / Aérospatial / Med-Tech, etc., etc. La réponse à votre question dépend de ce qui suit de système intégré que vous faites.

Les raisons pour lesquelles il est banni des systèmes intégrés d'intégrité élevée n'est pas seulement les fuites de mémoire potentielles, mais également beaucoup de comportement indéfini / indéterminé / non spécifié / non spécifié (non spécifié) asocié avec ces fonctions.

Edit: J'ai aussi oublié de mentionner la fragmentation du tas, qui est un autre danger. En outre, MISRA-C mentionne également "l'incohérence des données, l'épuisement de la mémoire, le comportement non déterministe" comme des raisons pour lesquelles il ne devrait pas être utilisé. Les deux premiers semblent plutôt subjectifs mais non déterministes sont définitivement quelque chose qui n'est pas autorisé dans ce type de systèmes.

Références:

  • MISRA-C: 2004 Règle 20.4 "L'attribution de la mémoire de tas dynamique ne doit pas être utilisée."
  • CEI 61508 Sécurité fonctionnelle, 61508-3 Annexe B (normative) Table B1,> Sil1: "Pas d'objets dynamiques", "Pas de variables dynamiques".

12 commentaires

C'est la seule bonne réponse. Vous ne devez jamais utiliser la mémoire de tas dans des systèmes embarqués. Placez toutes les données dans la section de données, BSS ou sur la pile. De cette façon, vous avez une empreinte de mémoire de taille fixe et vous pouvez calculer votre utilisation de la mémoire. De cette façon, vous savez avec certitude la quantité de mémoire que vous utilisez réellement et vous ne pouvez jamais dépasser cette limite. L'utilisation de tas est le vecteur le plus courant dans la fabrication d'un crash de systèmes incorporé après une course plus longue.


J'ai compris la question liée à Realloc () en particulier, pas sur l'utilisation d'une allocation de mémoire dynamique ou non.


@DIPSWITCH - Est-ce que l'utilisation du tas provoque un crash? Ou une utilisation invalide de crash de cause à un tas? Sentez la différence .. Vous pouvez vous planter beaucoup plus facilement - à tort utiliser des pointeurs .. - Devrions-nous désactiver les pointeurs?


@DIPSWITCH: Maintenant que nous avons des "systèmes intégrés" avec 64 MEGS ou même un demi-gigaoctet de RAM, "Jamais" ne s'applique plus.


@pmod La question était de savoir si REALLOC () est dangereux ou non. La réponse est, oui c'est, tout comme toute forme d'allocation de mémoire dynamique.


Il n'est pas tout à fait vrai que vous devriez "jamais" utiliser le tas dans des systèmes embarqués, mais vous devez prouver (sur la base de votre programme et l'allocator de la mise en œuvre) que la fragmentation et l'utilisation de la mémoire restent limitées de sorte qu'une allocation n'échouera jamais. Ceci est généralement presque impossible, mais un moyen simple est d'avoir un schéma d'allocation fixe au démarrage et aucune autre allocations. Il existe également d'autres cas faciles, comme si le tas est normalement inutilisé, à l'exception d'une opération qui effectue de nombreuses allocations suivies immédiatement par les libertés correspondants.


Si l'on appelle MALLOC () au démarrage, puis n'appelez jamais gratuitement (), le problème de la fragmentation de la mémoire ne se produit jamais. Notez également que realloc () est significativement plus compliqué que MALLOC (). Voir pour Exampe Steve Maguire's Book 'Code Solid Code "où il consacre plusieurs pages avec critique de Realloc ().


@Frefreico Si vous appelez MALLOC au démarrage et jamais, pourquoi n'avez-vous pas alloué la mémoire statiquement en premier lieu?


@LUNDIN: Au moment de la compilation, vous n'avez peut-être pas besoin d'informations sur la taille des objets ou le nombre d'objets à allouer. Ces informations peuvent être stockées sur Flash ou SD-CARD (par exemple en tant que fichier de configuration).


@Frederico qui n'a pas d'importance. Vous devriez toujours réserver la taille du tas pour la plus grande quantité de mémoire que vous rencontrerez jamais dans le flash. Vous pouvez donc allouer un tas ou un tableau statique, il n'y a pas de différence, à l'exception de l'ancien être plus lent et non confortable. Un tas n'est significatif que si vous avez besoin d'allouer de la mémoire pendant l'exécution.


L'utilisation d'une allocation de mémoire dynamique peut fournir un code de nettoyage. Vous pouvez également utiliser des bibliothèques qui attribue la mémoire de manière dynamique.


@LUNDIN: Un scénario mondial réel où j'ai utilisé une allocation semblable à un tas était un système intégré qui était censé contenir autant de données en RAM que cela conviendrait. Si j'avais compilé-le temps a alloué le stockage, je devais alors définir ma taille statique à une valeur inutilement petite, sinon rétrécir mon allocation de compilation à tout moment, j'ai ajouté autre chose qui allouerait statiquement un autre RAM) . Comme c'était, j'ai défini ma spécification de liaison pour forcer une variable à aller juste après la plus haute allocation statique et forcez une autre variable à la fin de la RAM. L'espace entre eux est devenu mon tas.



0
votes

Eh bien, il vaut mieux éviter d'utiliser RealLoc si c'est possible, car cette opération est particulièrement mixte dans la boucle: par exemple, si une mémoire allouée doit être étendue et qu'il n'y a pas d'espace entre après le blocage actuel et la prochaine allouée Bloc - Cette opération est presque égale: MALLOC + MEMCOPY + GRATUITEMENT.


4 commentaires

Est realloc () tout pire que malloc () / gratuit () ?


Pire car la réaffectation peut être optimisée en utilisant des blocs de mémoire adjacents, mais cela n'est bien sûr pas toujours possible


@pmod: un appel individuel à realloc ne doit jamais être pire que malloc / memcpy / libre , car il pourrait Toujours juste faire cela, et cela pourrait éviter le memcpy .


Désolé de jouer avec la négation, tout ce que je voulais dire "au moins ce n'est pas pire, mais statistiquement mieux" qui dépend de la mise en œuvre



2
votes
  1. realloc peut échouer, tout comme masloc peut. C'est une raison pour laquelle vous ne devez probablement pas utiliser dans un système intégré.

  2. realloc est pire que MALLOC dans lequel vous aurez besoin d'avoir les nouveaux et les nouveaux pointeurs valides pendant le realloc . En d'autres termes, vous aurez besoin de 2x l'espace mémoire de l'original malloc , plus tout montant supplémentaire (en supposant realloc augmente la taille du tampon).

  3. Utiliser realloc sera très dangereux, car il peut renvoyer un nouveau pointeur à votre emplacement de mémoire. Cela signifie:

    • Toutes les références à l'ancien pointeur doivent être corrigées après realloc .
    • Pour un système multi-threadé, le realloc doit être atomique. Si vous désactivez les interruptions pour y parvenir, le temps realloc peut être suffisamment long pour provoquer une réinitialisation matérielle par le chien de garde.

      Mise à jour : Je voulais juste préciser clairement. Je ne dis pas que realloc est pire que de mettre en œuvre realloc à l'aide d'un malloc / gratuit . Ce serait tout aussi mauvais. Si vous pouvez faire un seul malloc et gratuit , sans redimensionner, il est légèrement meilleur, mais toujours dangereux.


3 commentaires

Ne poserait pas les points 2 et 3 appliquer pour appeler manuellement masloc () / gratuit () ?


3. Est un bon point, Realloc est en effet plus dangereux que MALLOC pour cette raison, même si Malloc seul est considéré comme trop dangereux pour commencer.


@shachartooth - Droite, Realloc ne fait que malloc / gratuit dans certains cas. Donc, ma réponse tente d'expliquer que Realloc n'est pas magique et dangereux. Il n'est peut-être pas clair que les dragons sont, à moins que l'on implémente Realloc utilisant une API MALLOC / FREE. Je voulais juste appeler directement la mémoire au-dessus de la mémoire.



1
votes

Les problèmes avec REALLOC () dans les systèmes embarqués ne sont pas différents de ceux de tout autre système, mais les conséquences peuvent être plus graves dans des systèmes dans lesquels la mémoire est plus contrainte et que les semblables d'échec moins acceptables.

Un problème non mentionné jusqu'à présent est que REALLOC () (et toute autre opération de mémoire dynamique pour cette affaire) est non déterministe ; C'est ce que l'heure d'exécution est variable et imprévisible. De nombreux systèmes embarqués sont également les systèmes en temps réel et dans ces systèmes, comportement non déterministe est inacceptable.

Un autre problème est celui de la sécurité thread-sécurité. Vérifiez la documentat de votre bibliothèque pour voir si votre bibliothèque est en sécurité pour une allocation de mémoire dynamique. Généralement, si c'est le cas, vous devrez mettre en œuvre des talons mutex pour l'intégrer à votre bibliothèque de thread ou à votre RTO.

Tous les systèmes EMEBDDED ne se ressemblent pas; Si votre système intégré n'est pas en temps réel (ni le processus / la tâche / la tâche en question n'est pas en temps réel, et est indépendant des éléments en temps réel), et vous avez de grandes quantités de mémoire inutilisées ou de capacités de mémoire virtuelle, Ensuite, l'utilisation de Realloc () peut être acceptable, si elle est peut-être mal avérée dans la plupart des cas.

Plutôt que d'accepter la "sagesse conventionnelle" et la mémoire dynamique de la barre, mais vous devez comprendre vos besoins système et le comportement de la mémoire dynamique fonctionne et apportez une décision appropriée. Cela dit, si vous construisez un code de rééquivité et de la portabilité à une large gamme de plates-formes et d'applications que possible, la réaffectation est probablement une très mauvaise idée. Ne le cache pas dans une bibliothèque par exemple.

Remarque également que le même problème existe avec des classes de conteneurs C ++ STL qui réaffectent de manière dynamique et copier des données lorsque la capacité de conteneur est augmentée.


0 commentaires

4
votes

Dans de nombreux systèmes intégrés, un gestionnaire de mémoire personnalisé peut offrir une meilleure sémantique que disponible avec Malloc / Realloc / Gratuit. Certaines applications, par exemple, peuvent être utilisées avec un simple allocator de marque et de libération. Gardez un pointeur au début de la mémoire non encore allouée, allouer des choses en déplaçant le pointeur vers le haut et en les jetant en déplaçant le pointeur en dessous d'eux. Cela ne fonctionnera pas s'il est nécessaire de bloquer certaines choses tout en gardant d'autres choses qui ont été allouées après eux, mais dans des situations où cela n'est pas nécessaire, l'allocator de marque et la libération est moins cher que toute autre méthode d'allocation. Dans certains cas où l'allocator de marque et la libération n'est pas assez bon, il peut être utile d'allouer certaines choses dès le début du tas et d'autres choses à partir de la fin du tas; On peut libérer les choses allouées d'une extrémité sans affecter ceux alloués de l'autre.

Une autre approche pouvant parfois être utile dans des systèmes de multitâche ou de coopération-multicotage consiste à utiliser des poignées de mémoire plutôt que des pointeurs directs. Dans un système typique de la poignée, il y a une table de tous les objets alloués, construits en haut de la mémoire travaillant vers le bas et les objets eux-mêmes sont alloués à partir de bas en haut. Chaque objet alloué en mémoire détient une référence à la fente de table qui se réfère (si elle est en direct) ou d'une indication de sa taille (si mort). L'entrée de la table pour chaque objet tiendra la taille de l'objet ainsi qu'un pointeur à l'objet en mémoire. Les objets peuvent être attribués en trouvant simplement une fente de table gratuite (facile, car les fentes de table sont toutes des formes fixes), stockant l'adresse de la fente de table de l'objet au début de la mémoire libre, stockant l'objet lui-même juste au-delà de cela et mettez à jour le début. de mémoire libre à pointer juste après l'objet. Les objets peuvent être libérés en remplaçant la référence arrière avec une indication de longueur et libérant l'objet dans la table. Si une allocation échouerait, déplacez tous les objets en direct commençant par le haut de la mémoire, écrasant des objets morts et mettez à jour la table d'objets pour indiquer leurs nouvelles adresses.

La performance de cette approche est non déterministe, mais la fragmentation n'est pas un problème. En outre, il peut être possible dans certains systèmes multitâches coopératifs d'effectuer une collecte des ordures "en arrière-plan"; À condition que le collecteur des ordures puisse compléter une passe dans le temps qu'il faut pour effacer dans la zone de relâchement, les attentes longues peuvent être évitées. En outre, une logique "générationnelle" assez simple peut être utilisée pour améliorer les performances moyennes aux dépens des performances des pires cas.


0 commentaires