Auteur Sujet: Bibliothèque Accessories  (Lu 355 fois)

lapive

  • Newbie
  • *
  • Messages: 4
    • Voir le profil
Bibliothèque Accessories
« le: mai 21, 2018, 06:11:46 pm »
Bonjour,

Un message pour Thierry et sa bibliothèque Accessories:

En utilisant la bibliothèque Accessories, j'ai constaté une fuite de mémoire. Cela se produit si un Accessory a un debounceDelay > 0. Car dans ce cas, un empilement des évènements reçu pendant le debounceDelay a lieu ce qui réserve de la mémoire et cela est normal.

Le programme pour mettre en évidence le problème est très simple: un bouton poussoir qui active/désactive un relais.
Voici le programme.
#include "Commanders.h"
#include <Accessories.h>
#include <MemoryUsage.h>

const int buttonPin = 3; // broche du poussoir
const int relaisPin = 4; // broche du relais

ButtonsCommanderPush Bouton;
PortOnePin           Port;
AccessoryLight       Relais;

void ReceiveEvent(unsigned long inId, COMMANDERS_EVENT_TYPE inEventType, int inEventData)
{
Accessories::ReceiveEvent(inId, (ACCESSORIES_EVENT_TYPE)inEventType, inEventData);
}
void setup()
{
Serial.begin(115200); // console ARDUINO PC

Commanders::begin(ReceiveEvent);
Accessories::begin();

Bouton.begin(100, buttonPin);

Port.begin(relaisPin, DIGITAL_INVERTED);
Relais.begin(&Port, 100);

// Cas 1, Je fixe un debounce de 0s => tout ce passe bien
// Relais.SetDebounceDelay(0);

// Cas 2, Je fixe un debounce de 2s pour mettre en évidence le fait que la RAM libre diminue
Relais.SetDebounceDelay(2000);
PRINT_COMMANDERS()
PRINT_ACCESSORIES
}
void loop(void)
{
MEMORY_PRINT_FREERAM
Commanders::loop();
Accessories::loop();
}

Deux cas sont à considérer:

- Cas 1: je mets Relais.SetDebounceDelay(0), soit pas de temps de debounce et tout ce passe correctement: la RAM libre est stable.

- Cas 2: je mets Relais.SetDebounceDelay(2000), soit un debounce de 2 secondes (volontairement excessif pour mettre en évidence ce cas) pour actionner le relais.
Un premier appui sur le BP puis un deuxième avant 2s pour provoquer le debounce, et là, à chaque message "debounce : cant move !", un empilement a lieu (pour mémoriser l'évènement qui ne peut être exécuter tout de suite) réservant à chaque boucle de la RAM jusqu'à ce que le temps du debounce soit écoulé.

Après analyse, les événements mémorisés sont bien "dépilés" et exécutés, mais la mémoire utilisée n'est pas libérée, ce qui à terme fait qu'un nouveau "new" n'aura plus de mémoire pour "empiler" de nouveaux évènements qui seront alors perdus.

J'ai regardé dans le fichier Accessories.cpp dans la méthode Accessories::loop() où l'on "dépile" les évènements en attente, à priori c'est
Action *act = ActionsStack::Actions.GetActionToExecute();
if ( act != NULL )
Accessory::ExecuteEvent(act->Id, act->Event, act->Data);
J'ai testé un delete à l'endroit suivant:
Action *act = ActionsStack::Actions.GetActionToExecute();
if ( act != NULL )
{
Accessory::ExecuteEvent(act->Id, act->Event, act->Data);
delete act; // libère la mémoire de l'évènement précédemment exécuté
}
La RAM libre est stable. Je ne sais pas si c'est l'endroit le plus approprié pour ce delete, je ne connais pas les subtilités de Accessories ! :)

En espérant contribuer à la consolidation des fondations de Accessories !
Cyrille

Thierry

  • Global Moderator
  • Sr. Member
  • *****
  • Messages: 443
    • Voir le profil
Re : Bibliothèque Accessories
« Réponse #1 le: mai 26, 2018, 11:28:55 am »
Merci encore pour ce signalement.
Le problème est corrigé un peu différemment, mais corrigé quand même dans la version 1.1.3 disponible sur GitHub.
La raison de la différence de correction tient dans une règle que j'applique partout : ce que fait une classe, c'est elle qui doit le défaire si besoin. Dans ce cas de figure, c'est ActionsStack qui alloue la place pour l'action, c'est à elle de libérer cette place. Le respect de la règle, c'est l'assurance que tout ce qui doit être fait pour défaire sera bien fait. Et si plusieurs intervenants ont besoin de défaire quelque chose et qu'un simple delete ne suffit pas, l'appel à la bonne fonction fera le boulot complet.