Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String array not deallocated upon scope exit

Tags:

c

arduino

I am running into some serious memory leaks in my application, so I setup this extremely bare solution to test what happens when a String array goes out of scope...

I know that the old TextString implementation of String was lacking a destructor, but this current implementation seems to have it.

I am using this MemoryFree library (Note this linked code has now been fixed based on the accepted answer to this question).

The code examines two scenarios: Allocation of char array and string array in two different functions to force scope exit on both.

#include <MemoryFree.h>

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  int freeBefore, freeAfter;

  //TEST ALLOCATION OF CHAR ARRAY//
  freeBefore = freeMemory();
  AllocateCharArr();
  freeAfter = freeMemory();
  Serial.println("CHAR*: Before " + String(freeBefore)
    + ", After " + String(freeAfter)
    + ", Diff " + String(freeBefore - freeAfter));

  //TEST ALLOCATION OF STRING//
  freeBefore = freeMemory();
  AllocateStringArr();
  freeAfter = freeMemory();
  Serial.println("STRING: Before " + String(freeBefore)
    + ", After " + String(freeAfter)
    + ", Diff " + String(freeBefore - freeAfter));
}

void AllocateCharArr() {
  char s[100];
}

void AllocateStringArr() {
  String s[100];
}

void loop() { /* empty */ }

Output:

CHAR*: Before 1710, After 1710, Diff 0
STRING: Before 1645, After 1309, Diff 336

How come the String array allocation is not wiped from memory?

like image 626
Silas Hansen Avatar asked Jan 15 '12 22:01

Silas Hansen


1 Answers

I have come across memory handling issues in Arduino versions prior to 1.0 when testing the String class (see forum post here).

The String constructor uses realloc internally and it's this (avr libc) dynamic memory handling that was causing the problems (due to the pointer to the top of the heap __brkval not being updated upon free()).

Run the following code to see these issues in versions 0023, 0022, etc. In Arduino 1.0 the code should show no memory leaks:

#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include <HardwareSerial.h>
#include <MemoryFree.h>

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  int freeBefore, freeAfter;

  freeBefore = freeMemory();

  void* buffer = malloc(10);
  if (buffer == 0) {
    Serial.println("Failed to allocate memory");
  }
  free(buffer);

  freeAfter = freeMemory();
  Serial.println("Before " + String(freeBefore)
    + ", After " + String(freeAfter)
    + ", Diff " + String(freeBefore - freeAfter));
}

void loop() {
}

In addition, the MemoryFree library you are using can give wrong results as it doesn't take into account the free list. Try this updated version of MemoryFree.cpp:

extern unsigned int __heap_start;
extern void *__brkval;

/*
 * The free list structure as maintained by the 
 * avr-libc memory allocation routines.
 */
struct __freelist {
  size_t sz;
  struct __freelist *nx;
};

/* The head of the free list structure */
extern struct __freelist *__flp;

#include "MemoryFree.h";

/* Calculates the size of the free list */
int freeListSize() {
  struct __freelist* current;
  int total = 0;

  for (current = __flp; current; current = current->nx) {
    total += 2; /* Add two bytes for the memory block's header  */
    total += (int) current->sz;
  }

  return total;
}

int freeMemory() {
  int free_memory;

  if ((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__heap_start);
  } else {
    free_memory = ((int)&free_memory) - ((int)__brkval);
    free_memory += freeListSize();
  }
  return free_memory;
}
like image 159
Matthew Murdoch Avatar answered Nov 13 '22 01:11

Matthew Murdoch