Comment puis-je visualiser la mémoire (SRAM) l'utilisation d'un RÉGULATEUR de programme?
J'ai rencontré un problème avec un programme en cours d'exécution sur un microcontrôleur AVR (ATMega328P). Je crois que c'est dû à une pile/tas de collision, mais je voudrais être en mesure de le confirmer.
Est il possible que je peux visualiser SRAM utilisation par la pile et le tas?
Remarque: le programme est compilé avec avr-gcc et utilise l'avr-libc.
Mise à jour: Le réel problème que j'ai, c'est que la fonction malloc de la mise en œuvre est un échec (de retour NULL
). Tous les malloc
ing qui se passe au démarrage et tous les free
ing arrive à la fin de l'application (ce qui en pratique n'est jamais depuis la partie principale de l'application est dans une boucle infinie). Donc, je suis sûr que la fragmentation n'est pas la question.
- Wow. Vous devez être la seule personne à avoir jamais utilisé la fonction malloc sur un atmega. Je suis surpris qu'ils fonctionnent! Le jamais utilisé de même être inclus.
- Quelques conseils AVR spécifiques malloc choses sont abordés ici: nongnu.org/avr-libc/user-manual/malloc.html
Vous devez vous connecter pour publier un commentaire.
Vous dire malloc est d'échouer et retourner NULL:
La cause évidente qui vous devriez regarder la première est que votre tas est "plein" - je.e, le mémoire que vous avez demandé à malloc, ne peut être attribuée, car il n'est pas disponible.
Il y a deux scénarios de garder à l'esprit:
un: Vous avez un 16 K tas, vous avez déjà malloced 10 K et que vous essayez et de malloc un autre 10K. Votre tas est tout simplement trop petit.
b: le Plus souvent, vous avez un 16 k Tas, vous avez fait un tas de malloc/free/realloc appels et votre tas est inférieur à 50% "complète": Vous appelez la fonction malloc pour 1K et il ne parvient pas - quoi de neuf? Réponse - le segment de l'espace libre est fragmenté, il n'y a pas un états contigus 1K de mémoire libre qui peut être retourné. C gestionnaires de Tas peut pas compacter le tas lorsque cela se produit, alors vous êtes généralement dans le mauvais sens. Il existe des techniques pour éviter la fragmentation, mais il est difficile de savoir si c'est vraiment le problème. Vous devez ajouter la journalisation des cales pour le malloc et free de sorte que vous pouvez obtenir une idée de ce que la mémoire dynamique opérations.
EDIT:
Vous dire toutes les mallocs se produire au démarrage, de sorte que la fragmentation n'est pas la question.
Dans ce cas, il devrait être facile à remplacer l'allocation dynamique statique.
ancien exemple de code:
nouveau code:
Une fois que vous avez fait cela partout, votre éditeur de liens doit vous avertir si tout ne peut pas tenir dans la mémoire disponible. N'oubliez pas de réduire la taille de segment de mémoire - mais méfiez-vous que certains d'exécution io fonctions du système peuvent toujours utiliser le tas, donc vous ne pouvez pas être en mesure de le supprimer entièrement.
Vous pouvez vérifier la mémoire RAM statique utilisation de l'aide
avr-size
utilitaire, comme il est décrit dans lahttp://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=62968,
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=82536,
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=95638,
et http://letsmakerobots.com/node/27115
avr-size -C -x Filename.elf
(avr-taille documentation: http://ccrma.stanford.edu/planetccrma/man/man1/avr-size.1.html )
Suit un exemple de la façon de mettre cette IDE:
Sur Code::Blocks, Projet -> Build options -> Pré/post étapes de génération -> Post-étapes de génération, comprennent:
avr-size -C $(TARGET_OUTPUT_FILE)
ou
avr-size -C --mcu=atmega328p $(TARGET_OUTPUT_FILE)
Exemple de sortie à la fin de la construction:
De données est votre SRAM utilisation, et c'est seulement le montant que le compilateur
sait au moment de la compilation. Vous avez également besoin d'espace pour les choses créées à
d'exécution (en particulier de l'utilisation des piles).
Pour vérifier l'utilisation des piles (dynamic RAM),
de http://jeelabs.org/2011/05/22/atmega-memory-use/
Voici une petite fonction d'utilité qui détermine la quantité de mémoire RAM
actuellement inutilisés:
Et voici un croquis à l'aide de ce code:
La freeRam() renvoie le nombre d'octets existe entre la fin de la tas et de la dernière mémoire allouée sur la pile, donc c'est effectivement la façon dont beaucoup de la pile/tas peut grandir avant qu'ils entrent en collision.
Vous pouvez vérifier le retour de cette fonction autour de code vous pensez peut être à l'origine de la pile/tas de collision.
freeRam()
de fonction tel que défini ici échoue dans le cas où la mémoire libérée, est détenu à la malloc 'liste'. C'est seulement susceptible d'être un problème, dans la pratique, si la mémoire est souvent alloué dynamiquement et désalloué - probablement l'un des rares scénario sur un RÉGULATEUR de tension (par exemple, dans mon cas, je suis allouer dynamiquement de la mémoire lors de l'initialisation du programme uniquement dans lefreeRam()
code fonctionne pour moi).L'approche habituelle serait de remplir la mémoire avec un modèle connu et ensuite de vérifier les zones qui sont écrasés.
freeRam()
méthode ne peut pas l'attraper.Si vous utilisez à la fois la pile et le tas, alors il peut être un peu plus délicat. Je vais vous expliquer ce que j'ai fait lorsque aucun segment de mémoire est utilisé. En règle générale, toutes les entreprises, j'ai travaillé dans le domaine de la C embarqué logiciels) ont évité à l'aide de tas pour les petits les projets intégrés—pour éviter l'incertitude de mémoire dans la mémoire de la disponibilité. Nous utilisons de manière statique les variables déclarées à la place.
Une méthode consiste à remplir la plupart de la pile avec un modèle connu (par exemple, 0x55) au démarrage. Ceci est habituellement fait par un petit morceau de code au début de l'exécution du logiciel, soit au tout début de main(), ou peut-être même avant main() commence, dans la start-up code. Prenez soin de ne pas écraser la petite quantité de pile à ce moment là bien sûr. Puis, après avoir lancé le logiciel pendant un certain temps, vérifiez le contenu de l'espace de pile et de voir où la 0x55 est toujours intacte. Comment vous "inspecter" dépend de votre matériel cible. En supposant que vous avez un débogueur connecté, vous pouvez tout simplement arrêter le micro en cours d'exécution et de lecture de la mémoire.
Si vous avez un débogueur qui peut faire un accès à la mémoire de point d'arrêt (un peu plus de fantaisie que l'habitude d'exécution de point d'arrêt), alors vous pouvez définir un point d'arrêt dans un emplacement de pile—comme la plus éloignée de la limite de votre espace de pile. Qui peut être extrêmement utile, car il vous montre exactement ce bout de code est en cours d'exécution quand il aura atteint l'ampleur de l'utilisation des piles. Mais il exige de votre débogueur pour soutenir l'accès à la mémoire de point d'arrêt de la fonctionnalité et c'est pas souvent trouvé dans le "bas de gamme" débogueurs.
Si vous êtes également à l'aide d'un segment, alors il peut être un peu plus compliqué, car il peut être impossible de prédire où la pile et le tas va entrer en collision.
De ne pas utiliser le tas /allocation dynamique sur des cibles embarquées. Surtout avec un processeur avec de telles ressources limitées. Plutôt revoir la conception de votre application parce que le problème va se reproduire en tant que votre programme se développe.
En supposant que vous êtes en utilisant une seule pile (donc pas d'un RTOS ou quoi que ce soit) et que la pile est à la fin de la mémoire, de croissance vers le bas, tandis que le segment est à partir de la BSS/région de DONNÉES, le fait de grandir. J'ai vu des implémentations de malloc qui fait vérifier la stackpointer et échouent sur une collision. Vous pouvez essayer de le faire.
Si vous n'êtes pas en mesure d'adapter la fonction malloc de code, vous pouvez choisir de mettre votre pile de jetons au début de la mémoire (à l'aide de l'éditeur de liens de fichiers). En général, il est toujours une bonne idée de savoir/définir la taille maximale de la pile. Si vous vous mettez au début, vous recevrez un message d'erreur sur la lecture au-delà du début de la RAM. Le Tas sera à la fin et ne peut pas croître au-delà de la fin si c'est un décent mise (renvoie la valeur NULL à la place). La bonne chose est que vous savez avoir séparer les 2 cas d'erreur de 2 points distincts.
De trouver le maximum de la taille de la pile, vous pouvez remplir votre mémoire avec un motif, exécutez l'application et voir jusqu'où il est allé, voir également la réponse de Craig.
Si vous pouvez modifier le code de votre tas, vous pourriez pad avec un couple d'octets supplémentaires (délicat sur de faibles ressources) sur chaque bloc de mémoire. Ces octets pourrait contenir un schéma connu, différente de la pile. Cela pourrait vous donner un indice si il entre en collision avec la pile en la voyant apparaître à l'intérieur de la pile, ou vice versa.
Sur des systèmes d'exploitation Unix une fonction de la bibliothèque nommée sbrk() avec un paramètre de 0 vous permet d'accéder à la plus haute adresse allouée dynamiquement la mémoire du tas. La valeur de retour est un pointeur void * et pourrait être comparé à l'adresse de l'arbitraire d'un pile allouée variable.
En utilisant le résultat de cette comparaison doit être utilisé avec précaution. En fonction de la CPU et de l'architecture du système, la pile peut être de plus en plus vers le bas à partir d'un arbitraire haute adresse, tandis que l'allocation d'un tas déplacer vers le haut à partir de faible lié à la mémoire.
Parfois, le système d'exploitation a d'autres concepts pour la gestion de la mémoire (c'est à dire OS/9) qui met en tas et de la pile dans les différents segments de mémoire dans la mémoire libre. Sur ces systèmes d'exploitation - en particulier pour les systèmes embarqués - vous besoin de définir la quantité maximale de mémoire besoins de votre
applications à l'avance afin de permettre au système d'allouer de la mémoire des segments de tailles correspondantes.