bug in initializing/destroing objects in array allocated with new[] operator

Hello, guys!

I was working with dynamic allocation of arrays of objects and some unexpected bugs appeared.
I discover that was related to initializing and destructing the objects in the array.
That is not done using malloc (realloc, and others) and free.

So i try using new operator (and delete) and i discover that (on the Arduino platform) they do not do this work too.

When i use some simple objects there is no problem. However, when the object internally allocate memory too (like the String object), that memory is not deallocated (because the destructor is not being called).

Here is an example to clarify:

#include "MemoryFree.h"

void setup(){
  Serial.begin(9600);
  //Prints initial free memory
  printFreeMemory();
  
  //do some allocating and deallocating
  allocateDeallocate();
  
  //The free memory should be the same
  printFreeMemory();
}

void allocateDeallocate(){
  for(int i=0; i < 5; ++i){
      String * strings = new String[5];
      delete strings;
  }
}

void loop(){
}


void printFreeMemory(){
  Serial.print("freeMemory: ");Serial.println(freeMemory());
}

I am using the MemoryFree library (http://playground.arduino.cc//Code/AvailableMemory) to display the use of RAM.

I look on the new.cpp file on the Arduino software and it is just making a call to malloc and free (without initializing or destructing nothing).

void * operator new(size_t size)
{
  return malloc(size);
}

void * operator new[](size_t size)
{
  return malloc(size);
}

void operator delete(void * ptr)
{
  free(ptr);
}

void operator delete[](void * ptr)
{
  free(ptr);
}

Finally i found on this post (http://stackoverflow.com/questions/11401633/call-constructor-for-object-array-allocated-with-malloc) a way to solve that.
The deallocating worked ok:

//For each item call the destructor
    for(int i =0; i < size; ++i){
        (&items[i])->~String(); 
    }
    //Free the array's memory
    free(items);

but the initialization generate a compilation error:

int size = 10;
    String * items = (String *)malloc(size * sizeof(String));
    
    for(int i =0; i < size; ++i){
        String * s = &items[i];
        new(s) String();
    }

error:

error: no matching function for call to ‘operator new(unsigned int, String*&)’
<path to Arduino>/Arduino/hardware/arduino/cores/arduino/new.h:10: note: candidates are: void* operator new(size_t)

I hope that someone can help me to solve this problem. And i think that this should be corrected on the Arduino code too.

Thanks to all.

      String * strings = new String[5];
      delete strings;

When you use new to create an array of pointers, you need to use to correct (array) version of delete:

delete [] strings;
//For each item call the destructor
    for(int i =0; i < size; ++i){
        (&items[i])->~String(); 
    }
    //Free the array's memory
    free(items);

You absolutely should not need to do that. Whoa.

Do what PaulS said.

void allocateDeallocate(){
  for(int i=0; i < 5; ++i){
      String * strings = new String[5];
      delete [] strings;
  }
}

Personally I wouldn’t be using String.

Please note that in versions of the IDE up to and including 1.0.3, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.), as described here for example.

Alternatively, install the fix described here: Fixing String Crashes

Preferably upgrade your IDE to version 1.0.4 or above at: http://arduino.cc/en/Main/Software

This modified version of your sketch proves it:

int memoryFree()
  {
  extern unsigned long __bss_end;
  extern void *__brkval;
  //  long myValue;
  int freeValue = 0;
  if ((unsigned long)__brkval == 0)
    freeValue = ((unsigned long)&freeValue) - ((unsigned long)&__bss_end);
  else
    freeValue = ((unsigned long)&freeValue) - ((unsigned long)__brkval);
  return freeValue;
  }  //end memoryFree

void setup()
  {
  Serial.begin(115200);
  Serial.println (memoryFree());
  //do some allocating and deallocating
  for(int i=0; i < 100; ++i)
    {
    String * strings = new String[5];
    delete [] strings;
    }
  Serial.println (memoryFree());
  } // end of setup

void loop() { }

Output:

1827
1827

I am using the MemoryFree library (Arduino Playground - HomePage) to display the use of RAM.

When you ask for memory (eg new()) from the heap the heap may be extended (grown in size) if required. However the size of the heap will not be reduced in size when you use free etc.

Mark

Thank you, guys!

I really didn't know the "delete ".

In relation to Strings... i had read some about those bugs...
but current i am using version 1.0.5, and i think they were corrected, right?

I chose to use String object against the C-style, because they look so much powerful and elegant.
But i would like to know, if i use cstr how much space in RAM and program memory i could gain?

holmes4:
When you ask for memory (eg new()) from the heap the heap may be extended (grown in size) if required. However the size of the heap will not be reduced in size when you use free etc.

Mark, i was curious. You mean that the heap never decrease in size? This doesn't look right to me.

Att. Paulo

Power and elegance comes at a cost. You have no idea what is happening under the hood, and with the limited recources of an Arduino, that can be deadly.

souzabrizolara:
Mark, i was curious. You mean that the heap never decrease in size? This doesn’t look right to me.

I’m not sure that is strictly correct, however certainly if the outer part got allocated to something that was never freed then it couldn’t shrink. It could re-use gaps in the middle though.

Mark, i was curious. You mean that the heap never decrease in size? This doesn't look right to me.

Basically you don't know where in the heap the objects data space was created and therefore you can't tell if the heap can be reduced in size. Its part of a problem known as heap fragmentation. There is no real way of de-fraging the heap in C/C++. Also rember that the heap also contains the data structures used to keep track to the free space.

Mark

That sounds right. The heap may possibly shrink in size under ideal circumstances, but you certainly can't rely on it.

Out of curiosity I ran a quick test that malloced 500 bytes and then freed it. When I allocated the 500 bytes __brkval increased by 502 bytes; when I freed them, __brkval returned to the previous value. This indicates to me that the heap was expanded and contracted sensibly.

Yes, buy try

malloc/new objects a,b,c,d

then free a,b,c as d still exists and can't be moved the heap size can't be reduced!

then try

malloc/new a,b,c,d

and free a,b,d

Mark

Yes I'm aware of the issues of heap space being pinned and fragmented - I was just responding to your comment that the heap size would never be reduced, which I now think was inaccurate.

KeithRB:
Power and elegance comes at a cost. You have no idea what is happening under the hood, and with the limited recources of an Arduino, that can be deadly.

I think you are write. Dynamic allocation in Arduino really can be deadly (sometimes i suffer with that).
However, sometimes (and that is my case) you really need allocate memory dynamically.
For example, if you want to receive external data that you don't know previously what is and neither the size.
In that case, i believe that is best rely on String instead of do my own string's allocation, deallocation, ...

What do you think? I would love to know something that reduce my headaches with Strings and RAM use. ^^

souzabrizolara:
For example, if you want to receive external data that you don't know previously what is and neither the size.
In that case, i believe that is best rely on String instead of do my own string's allocation, deallocation, ...

What do you think?

I think that is the worst situation to use dynamic allocation because you have no control or visibility over whether and when you run out of RAM.

The right approach IMO in that situation is to design your sketch so that the buffer size is sufficient for the scenarios you expect to occur, and design the data processing so that it behaves sensibly if the buffer size is exceeded. It might mean you have to handle the incoming data as it arrives instead of waiting to buffer the whole thing, or discard the least valuable part of the data, or page it out to some external storage, or invoke flow control - usually, there will be some sensible way to deal with a buffer overflow.