Un petit problème dans mon code

Les String utilisent l'allocation dynamique.

L'allocation dynamique aboutit forcément à de la fragmentation mémoire.
Premièrement ce phénomène ralentit la recherche d'un nouveau bloc de mémoire libre.
Deuxièmement il peut aboutir à des erreurs d'allocation sur des blocs de taille importante.

En exécutant le code suivant, on constate bien que l'allocateur parvient à allouer au départ des blocs de plus de 100 octets, ensuite il plafonne à 89.

void setup() {
  Serial.begin(115200);
}

String generateRandomString() {
  String result;
  int l, len;
  len = l = random(10, 128);
  while (len--) result += '?';
  if (result.length() != l) {
    Serial.print(result.length());
    Serial.print(" / ");
    Serial.print(l);
    Serial.print(" : ");
    Serial.println("ERREUR D'ALLOCATION");
  }
  return result;
}

String strings[10];

void loop() {
  static float fragmentation, lastFragmentation;

  for (String &s : strings) {
    s = generateRandomString();
    Serial.print(s.length());
    Serial.print(" : ");
    Serial.println(s);
  }
  delay(100);
}
61 : ?????????????????????????????????????????????????????????????
15 : ???????????????
105 : ?????????????????????????????????????????????????????????????????????????????????????????????????????????
100 : ????????????????????????????????????????????????????????????????????????????????????????????????????
20 : ????????????????????
..............
..............
115 : ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????
24 : ????????????????????????
110 : ??????????????????????????????????????????????????????????????????????????????????????????????????????????????
43 : ???????????????????????????????????????????
57 : ?????????????????????????????????????????????????????????
42 : ??????????????????????????????????????????
50 : ??????????????????????????????????????????????????
36 : ????????????????????????????????????
88 / 92 : ERREUR D'ALLOCATION
88 : ????????????????????????????????????????????????????????????????????????????????????????
113 : ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????
104 : ????????????????????????????????????????????????????????????????????????????????????????????????????????
58 : ??????????????????????????????????????????????????????????
75 : ???????????????????????????????????????????????????????????????????????????
95 : ???????????????????????????????????????????????????????????????????????????????????????????????
123 : ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
54 : ??????????????????????????????????????????????????????
11 : ???????????
89 / 114 : ERREUR D'ALLOCATION
89 : ?????????????????????????????????????????????????????????????????????????????????????????
13 : ?????????????
89 / 97 : ERREUR D'ALLOCATION
89 : ?????????????????????????????????????????????????????????????????????????????????????????
24 : ????????????????????????
86 : ??????????????????????????????????????????????????????????????????????????????????????
89 / 105 : ERREUR D'ALLOCATION
89 : ?????????????????????????????????????????????????????????????????????????????????????????
57 : ?????????????????????????????????????????????????????????
33 : ?????????????????????????????????
89 / 111 : ERREUR D'ALLOCATION
89 : ?????????????????????????????????????????????????????????????????????????????????????????
89 / 125 : ERREUR D'ALLOCATION
89 : ?????????????????????????????????????????????????????????????????????????????????????????
88 : ????????????????????????????????????????????????????????????????????????????????????????
54 : ??????????????????????????????????????????????????????
89 / 103 : ERREUR D'ALLOCATION

@+

Ça veut dire quoi ça ?

  for (String &s : strings)

Bonjour,

C'est range for, un ajout au C++ dans la version C++11.

Merci, c'est compliqué mais intéressant

Moi aussi cela m'a surpris. Mon C++ date d'il y a longtemps.

@+

Pour ma part, j'ai un peu décortiqué String ces derniers temps.
Notamment à l'occasion du dev de ceci, qui contient une petite lib charBuffer pas très éloignée de String, mais en très simplifié.

Avec comme conclusion personnelle :
Faire de l'allocation/libération dynamique de mémoire avec des String n'est pas forcément un problème, tant qu'on maîtrise ce que l'on fait.

En général, si tout ce qui est alloué par une fonction est désalloué à la fin de la fonction (cas fréquent avec arduino, où on appelle une fonction depuis loop(), elle fait des tas de trucs, appelle d'autres fonction, alloue toutes sortes de variables temporaires libérées à la fin), cela ne pose aucun problème tant qu'on a une réserve de RAM suffisante au départ.

Perso dans mes programmes, j'essaye de faire en sorte qu'il y ait un max de RAM disponible en début de loop(), pour être large.
Et l'utilisation de la RAM est ensuite un peu comme le flux et reflux des vagues en bord de mer : on revient toujours au même point, et tant qu'on ne dépasse pas la hauteur de la digue, on garde les pieds au sec. :slight_smile:

Le danger de String arrive quand on utilise des instructions (au demeurant très pratiques) comme maChaine = maChaine + "la suite";
L'objet est désalloué / réalloué sur une taille plus grande, et là cela morcelle très vite la RAM disponible.
Si c'est à dose raisonnable, à l'intérieur d'une fonction, avec un objet systématiquement désalloué en fin de parcours, avec beaucoup de RAM disponible, ça se passe en général bien.
A l'inverse, si c'est un objet String alloué de manière statique en variable globale, et dont le contenu évolue fortement, le carnage est assuré.

En plus, le type de bug auquel on est confronté en cas de débordement mémoire, peut être très incidieux / difficile à diagnostiquer.

Donc l'un dans l'autre je déconseillerais String aux débutants.
Et pour les autres, ben... c'est chacun qui voit.
Perso je m'en passe très bien.

A noter que sur ESP la RAM est nettement moins exigue, donc l'usage de String y est nettement moins risqué.

En plus, le type de bug auquel on est confronté en cas de débordement mémoire, peut être très incidieux / difficile à diagnostiquer.
Donc l'un dans l'autre je déconseillerais String aux débutants.

Le problème est surtout là. Un débutant qui se trouve confronté à un problème d'allocation à cause de la fragmentation ne comprendra pas ce qui lui arrive, surtout que la fragmentation n'arrive pas dès la première exécution du programme. Cela peut prendre un certain temps.

@+

Tout à fait - c’est pour cela qu’il est important de signaler quand on peut faire autrement très simplement

Ensuite suivant le niveau et le besoin (code qui doit tourner longtemps) on peut guider dans un sens ou l’autre