Je voudrais savoir combien de RAM j'utilise dans mon projet, pour autant que je sache, il n'y a aucun moyen de résoudre cela (à part le parcourir et le calculer moi-même). Je suis arrivé à un stade dans un projet assez important où j'ai déterminé que je manque de RAM.
J'ai déterminé cela parce que je peux ajouter une section, puis tout l'enfer se déchaîne ailleurs dans mon code sans raison apparente. Si je #ifndef
quelque chose d'autre, ça marche à nouveau. Il n'y a rien de mal à programmer avec le nouveau code.
J'ai soupçonné pendant un moment que j'arrivais à la fin de la mémoire RAM disponible. Je ne pense pas que j'utilise trop de pile (bien que ce soit possible), quelle est la meilleure façon de déterminer la quantité de RAM que j'utilise réellement?
En passant par et en essayant de le résoudre, j'ai des problèmes quand j'arrive aux énumérations et aux structures; combien de mémoire coûtent-ils?
première édition: ÉGALEMENT, j'ai tellement édité mon croquis depuis le début, ce ne sont pas les résultats réels que j'ai initialement obtenus, mais c'est ce que j'obtiens maintenant.
text data bss dec hex filename
17554 844 449 18847 499f HA15_20140317w.cpp.elf
16316 694 409 17419 440b HA15_20140317w.cpp.elf
17346 790 426 18562 4882 HA15_20140317w.cpp.elf
La première ligne (avec le texte 17554) ne fonctionnait pas, après beaucoup de modifications, la deuxième ligne (avec le texte 16316) fonctionne comme il se doit.
edit: la troisième ligne a tout fonctionne, lecture en série, mes nouvelles fonctions, etc. J'ai essentiellement supprimé quelques variables globales et du code en double. Je mentionne cela parce que (comme suspect), il ne s'agit pas de ce code par sae, il doit être sur l'utilisation de la RAM. Ce qui me ramène à la question d'origine, "comment la mesurer au mieux". Je vérifie toujours quelques réponses, merci.
Comment puis-je réellement interpréter les informations ci-dessus?
Jusqu'à présent, ma compréhension est:
`TEXT` is program instruction memory
`DATA` is variables (unitialised?) in program memory
`BSS` is variables occupying RAM
puisque BSS est considérablement inférieur à 1024 octets, pourquoi le second fonctionne-t-il, mais pas le premier? Si c'est le cas, les DATA+BSS
deux occupent plus de 1024.
ré-éditer: j'ai édité la question pour inclure le code, mais maintenant je l'ai supprimé car cela n'avait vraiment rien à voir avec le problème (à part peut-être de mauvaises pratiques de codage, des déclarations de variables et autres). Vous pouvez consulter le code en parcourant les modifications si vous voulez vraiment le voir. Je voulais revenir à la question actuelle, qui était plus basée sur: Comment mesurer l'utilisation de la RAM.
String
type dans vos programmes? Ceci est connu pour effectuer des allocations et des libérations de mémoire dynamique fréquentes, ce qui peut fragmenter le tas au point où vous ne pouvez plus conserver de mémoire.String
s à cause des frais généraux. Je suis heureux de travailler avec des tableaux de caractères, cela dit, je définis presque toujours tous mes tableaux de caractères avec une taille fixe (pour le moment, j'ai un tableau de 1 octet qui n'est pas uniquement parce que je change la longueur du contenu pour différentes recompilations.Réponses:
Vous pouvez utiliser les fonctions fournies AVRGCC: Monitoring Stack Usage
La fonction était destinée à vérifier l'utilisation de la pile, mais elle signale la RAM réelle qui n'a jamais été utilisée (pendant l'exécution). Il le fait en "peignant" (remplissant) la RAM avec une valeur connue (0xC5), puis en vérifiant la zone RAM en comptant combien d'octets ont toujours la même valeur initiale.
Le rapport montrera la RAM qui n'a pas été utilisée (RAM libre minimale) et vous pouvez donc calculer la RAM maximale qui a été utilisée (RAM totale - RAM signalée).
Il y a deux fonctions:
StackPaint est exécuté automatiquement lors de l'initialisation et "peint" la RAM avec la valeur 0xC5 (peut être modifiée si nécessaire).
StackCount peut être appelé à tout moment pour compter la RAM qui n'a pas été utilisée.
Voici un exemple d'utilisation. Ne fait pas grand-chose mais vise à montrer comment utiliser les fonctions.
la source
Les principaux problèmes que vous pouvez rencontrer avec l'utilisation de la mémoire au moment de l'exécution sont les suivants:
malloc
ounew
)Les deux sont en fait les mêmes que l'AVR SRAM (2K sur Arduino) est utilisé pour les deux (en plus des données statiques dont la taille ne change jamais pendant l'exécution du programme).
En général, l'allocation dynamique de mémoire est rarement utilisée sur les MCU, seules quelques bibliothèques l'utilisent généralement (l'une d'entre elles est la
String
classe, que vous avez mentionnée que vous n'utilisez pas, et c'est un bon point).La pile et le tas peuvent être vus dans l'image ci-dessous (avec la permission d' Adafruit ):
Par conséquent, le problème le plus attendu provient du débordement de pile (c'est-à-dire lorsque la pile se développe vers le tas et déborde dessus, puis -si le tas n'a pas été utilisé du tout - déborde sur la zone de données statiques de la SRAM. À ce moment-là, vous avez un risque élevé:
Afin de connaître la quantité de mémoire qui reste entre le haut du tas et le haut de la pile (en fait, nous pourrions l'appeler le bas si nous représentons à la fois le tas et la pile sur la même image comme illustré ci-dessous), vous peut utiliser la fonction suivante:
Dans le code ci-dessus,
__brkval
pointe vers le haut du tas mais c'est0
quand le tas n'a pas été utilisé, auquel cas nous utilisons&__heap_start
qui pointe vers__heap_start
, la première variable qui marque le bas du tas;&v
pointe bien sûr vers le haut de la pile (il s'agit de la dernière variable poussée sur la pile), d'où la formule ci-dessus renvoie la quantité de mémoire disponible pour la pile (ou le tas si vous l'utilisez) pour croître.Vous pouvez utiliser cette fonction à divers endroits de votre code pour essayer de savoir où cette taille diminue considérablement.
Bien sûr, si jamais vous voyez cette fonction renvoyer un nombre négatif, il est trop tard: vous avez déjà survolé la pile!
la source
malloc
etnew
la seule façon de le faire? Si oui, alors je n'ai rien de dynamique. De plus, je viens d'apprendre que l'ONU a 2K de SRAM. Je pensais que c'était 1K. En tenant compte de cela, je ne manque pas de RAM! J'ai besoin de chercher ailleurs.calloc
. Mais vous utilisez peut-être des bibliothèques tierces qui utilisent l'allocation dynamique à votre insu (vous devez vérifier le code source de toutes vos dépendances pour en être sûr)Lorsque vous découvrez comment localiser le fichier .elf généré dans votre répertoire temporaire, vous pouvez exécuter la commande ci-dessous pour vider une utilisation SRAM, où
project.elf
doit être remplacé par le.elf
fichier généré . L'avantage de cette sortie est la possibilité d'inspecter la façon dont votre SRAM est utilisée. Toutes les variables doivent-elles être globales, sont-elles vraiment toutes requises?Notez que cela ne montre pas l'utilisation de la pile ou de la mémoire dynamique comme Ignacio Vazquez-Abrams l'a noté dans les commentaires ci-dessous.
De plus, un
avr-objdump -S -j .data project.elf
peut être vérifié, mais aucun de mes programmes ne produit quoi que ce soit avec cela, donc je ne peux pas dire avec certitude s'il est utile. Il était censé répertorier les «données initialisées (non nulles)».la source
avr-size
. Mais cela ne vous montrera pas les allocations dynamiques ou l'utilisation de la pile.avr-objdump
etavr-size
je vais modifier mon post ci - dessus sous peu. Merci pour cela.Il serait préférable d'utiliser une combinaison d'estimation manuelle et en utilisant l'
sizeof
opérateur. Si toutes vos déclarations sont statiques, cela devrait vous donner une image précise.Si vous utilisez des allocations dynamiques, vous pouvez rencontrer un problème une fois que vous commencez à désallouer la mémoire. Cela est dû à la fragmentation de la mémoire sur le tas.
Un enum prend autant d'espace qu'un
int
. Donc, si vous avez un ensemble de 10 éléments dans uneenum
déclaration, ce serait10*sizeof(int)
. De plus, chaque variable qui utilise une énumération est simplement unint
.Pour les structures, il serait plus facile à utiliser
sizeof
pour le savoir. Les structures occupent un espace (minimum) égal à la somme de ses membres. Si le compilateur effectue l'alignement de la structure, cela peut être plus, mais cela est peu probable dans le cas deavr-gcc
.la source
sizeof
à cet effet. À l'heure actuelle, j'ai près de 400 octets déjà comptabilisés (globalement). Maintenant, je vais parcourir et calculer les énumérations (manuellement) et les structures (dont j'ai quelques-unes et je vais utilisersizeof
), et faire un rapport.sizeof
de connaître la taille de vos données statiques car elles sont imprimées par avrdude IIRC.Il existe un programme appelé Arduino Builder qui fournit une visualisation nette de la quantité de flash, SRAM et EEPROM que votre programme utilise.
Le constructeur Arduino fait partie de la solution IDE Arduino CodeBlocks . Il peut être utilisé en tant que programme autonome ou via l'IDE Arduino CodeBlocks.
Malheureusement, Arduino Builder est un peu ancien, mais il devrait fonctionner pour la plupart des programmes et la plupart des Arduinos, comme Uno.
la source