Low Memory Warning: What's the best way to initialize an array?

Hello,

I’ve been working on a project at my university and it basically consists of creating 3 arrays of length 100 each, getting one set of data at each iteration and after 100 iterations, the code does some calculations with these arrays and it starts all over again.

I know there are two ways of declaring an array. You can either allocate memory manually with a pointer and the malloc() function or you can use type A. But for some reason, each way uses a different amount of memory. For instance:

using type A
This one uses 87% of dynamic memory (1,791 bytes) and I get a Low Memory warning.

int i=0;
int N=100;
float A[100];
float B[100]; 
float C[100];

void setup(){}

void loop(){
  if(i<N){
   A[i]=analogRead(0);
   B[i]=analogRead(2);
   C[i]=analogRead(4);
    i++;
  }
  else{
     calculate(A,B,C) // this is a void function
      i=0;
   }
}

using malloc():
This one uses only 29% of dynamic memory (597 bytes) and I don’t get a Low Memory Warning.

int i=0;
int N=100;
float *A=(float*)malloc(N*sizeof(float));
float *B=(float*)malloc(N*sizeof(float));
float *C=(float*)malloc(N*sizeof(float));

void setup(){}

void loop(){
  if(i<N){
   A[i]=analogRead(0);
   B[i]=analogRead(2);
   C[i]=analogRead(4);
    i++;
  }
  else{
     calculate(A,B,C) // this is a void function
      i=0;

      free(A);
      free(B);
      free(C);

      float *A=(float*)malloc(N*sizeof(float));
      float *B=(float*)malloc(N*sizeof(float));
      float *C=(float*)malloc(N*sizeof(float));
   }
}

My questions are:

  1. Why is there such a discrepancy in terms of memory usage between both methods? For what I understood, the only difference is that by using malloc, you are allocating memory manually.

  2. Which one would you guys recommend, given the size of the arrays could get even bigger in future steps of the project?

the compiler does not now what your code does.

--> So at compile time it did not allocate your memory, it's done at run time.

both options end up with the same amount of RAM being used.

you might want to explore the PROGMEM capabilities

1) Why is there such a discrepancy in terms of memory usage between both methods? For what I understood, the only difference is that by using malloc, you are allocating memory manually.

The amount of memory noted is ONLY that of global arrays, variables, and string literals - that is stuff whose size is fixed at run time.

2) Which one would you guys recommend, given the size of the arrays could get even bigger in future steps of the project?

Static arrays. At least with them you get some warning at compile time that you have a problem.

you might want to explore the PROGMEM capabilities

That would be useless since PROGMEM is read-only at run time.

PaulS:
The amount of memory noted is ONLY that of global arrays, variables, and string literals - that is stuff whose size is fixed at run time.
Static arrays. At least with them you get some warning at compile time that you have a problem.

But the optimal size would be about 1000 in the future. I’ve just tried that using float A[1000], and it didn’t compile because there’s not enough memory.

Is there no way around it other than maybe buying another microprocessor?

gui93: But the optimal size would be about 1000 in the future. I've just tried that using float A[1000], and it didn't compile because there's not enough memory.

Is there no way around it other than maybe buying another microprocessor?

3 arrays of 1000 floats equals 12000 bytes SRAM. Not quite sure why you use floats for analogRead.

And be aware; if your calculation function uses local variables, they are not counted at compile time. So you might think that you're safe, but that might not be the case.

Arduino Zero and MKR1000 seem to be the current Arduino choices. Maybe a Raspberry Pi with external ADC is a better option.

J-M-L: --> So at compile time it did not allocate your memory, it's done at run time.

both options end up with the same amount of RAM being used.

Actually malloc needs two bytes more per allocation to hold the length of the chunk.

Avrheap class - peek into the heap

sterretje: 3 arrays of 1000 floats equals 12000 bytes SRAM. Not quite sure why you use floats for analogRead.

And be aware; if your calculation function uses local variables, they are not counted at compile time. So you might think that you're safe, but that might not be the case.

Arduino Zero and MKR1000 seem to be the current Arduino choices. Maybe a Raspberry Pi with external ADC is a better option.

Yeah, I just realized analogRead is going to return a number from 0 to 1023 anyway, so I might as well just use int for the intermediate variable. Something like:

int temp=analogRead(0); A_=5*(temp/1023);_ But even so, the values would be floats (4.2 V, 2.4 V, ...), so the arrays would have to be floats.

Because a unit of 1/10 (1/100, 1/1000 or 5/1024) of a Volt is not possible?

There is no need for floats here, at least for the raw data.

Whandall: Because a unit of 1/10 (1/100, 1/1000 or 5/1024) of a Volt is not possible?

There is no need for floats here, at least for the raw data.

Sorry for the dumb question, but how can I store a value such as 4.2 in an int?

As 42 in 1/10, as 420 as 1/100, ....

You can do your calculations on integers and convert the final result to float (if needed). Or fixed point math instead of float.

BTW 4.2 is stored in a float with the value 4.1999998.

float conversion (interactive)

If you use 1/2n as a unit, it is easy to split the integral and fractional part with masks and/or shifts.

Or just store the values as ints in the arrays and just make them float when you need them. You can even use a macro.

KeithRB: Or just store the values as ints in the arrays and just make them float when you need them. You can even use a macro.

And the advantage of doing that is that integers take a smaller space than floats?

On the 8 bit Arduinos an integer is 2 bytes long and a float 4.

Is there no way around it

If you can perform the calculation on each sample, as it is read, you would not need to store them all and process them all at once. There aren’t many calculations I can think of that would require all the samples to be available at the same time. I guess replaying the samples in reverse order would require it… :-/

Cheers,
/dev

/dev: If you can perform the calculation on each sample, as it is read, you would not need to store them all and process them all at once. There aren't many calculations I can think of that would require all the samples to be available at the same time. I guess replaying the samples in reverse order would require it... :-/

Cheers, /dev

I'm acquiring AC voltage data. So I need a whole period in order to calculate things like RMS value and maximum value.

So, what I've been doing is:

Record N samples -> Use a function to break down the samples into complete periods -> Analyse

Right - the PROGMEM comment was of course for read only data, to get some space if you use strings or other stuff cluttering the RAM