memory free... ma siamo sicuri?

Ciao,
ho scritto uno sketch per capire meglio come funziona l'allocazione della memoria, forse non è il modo migliore ma devo inziare da qualche parte, comunque questo è lo sketch

#include <FreeMemory.h>

#define LEN_VET 1024

byte vet1[LEN_VET];

void setup() {                  
  Serial.begin(19200); 
  
  Serial.println(freeMemory());
  
  for(int i=0;i<LEN_VET;i++) {
    vet1[i] = i;
  }  

  Serial.println(freeMemory());  
  gen();   
  Serial.println(freeMemory());    
}

void loop() {        
//...  
}

void gen()
{
     byte vet2[LEN_VET];
     
     for(int i=0;i<LEN_VET;i++) {
        vet2[i] = i;
        //Serial.print(vet2[i]);
     } 
     Serial.println(freeMemory());   
}

il riusltato è

816
816
814
816

dopo l'istanza del primo vettore sono disponibili 816 byte ?
La quantità di memoria anche dopo l'allocazione non cambia (va bhè qui era scontato ma volevo conferma).
La cosa che più non comprendo è che nella funzione gen() alloco di nuovo un vettore pari al primo, e la memoria disponibile in quel momento è di 814 :relaxed: ?!?! ma come ho allocato un array di 1024 e mi occupa solo 2 byte?
Finita la funzione la memoria ritorna al valore di prima.
Qualcuno saprebbe dirmi cosa succede?
ah... dimenticavo è con Arduino uno

Grazie

vet2 è una "variabile locale"..quando esci dalla funzione che l'ha creata,ossia gen,viene disallocata...

m_ri:
vet2 è una "variabile locale"..quando esci dalla funzione che l'ha creata,ossia gen,viene disallocata...

Quoto. Dichiara vet2 globale.

BigByte:
dopo l'istanza del primo vettore sono disponibili 816 byte ?

Nei 2048 byte di SRAM non ci sta solo il vettore di 1024 byte che hai dichiarato ma anche tutte le altre variabili create dal programma (stai usando la seriale, che è una libreria contenuta nel core, poi stai usando la libreria esterna FreeMemory) nonché lo stack del programma.

leo72:

BigByte:
dopo l'istanza del primo vettore sono disponibili 816 byte ?

Nei 2048 byte di SRAM non ci sta solo il vettore di 1024 byte che hai dichiarato ma anche tutte le altre variabili create dal programma (stai usando la seriale, che è una libreria contenuta nel core, poi stai usando la libreria esterna FreeMemory) nonché lo stack del programma.

Si ok su questo ci siamo. Quello che non capisco è: se io dichiaro vet1 come globale io mi aspetto che sia allocato staticamente ed infatti la freeMemory() mi dice che ho liberi solo 816byte, nel momento in cui io chiamo la funzione nella quale è dichiarato vet2 di 1024byte questo deve essere allocato in memoria e se chiamo la freeMemory() mi dovrebbe dare 0 o comunque dovrebbe bloccarsi ed invece la freeMemory mi dà 814byte, cioè come se avesse allocato solo un puntatore....Perchè?

a occhio direi che il compilatore ignora il vettore2..tieni conto che nelle ottimizzazioni elimina variabili/array e funzioni non utilizzate,può cancellare di brutto i for e tante altre cose...
e te dichiari vettori non utilizzati..

m_ri:
a occhio direi che il compilatore ignora il vettore2..tieni conto che nelle ottimizzazioni elimina variabili/array e funzioni non utilizzate,può cancellare di brutto i for e tante altre cose...
e te dichiari vettori non utilizzati..

Si ok ma come vedi nella funzione ho sia scritto nel vettore2 ed anche stampato, e il risultato non cambia. Ma la cosa più assurda è che se il vet2 lo dichiaro di 9000byte ed eseguo tutto funziona come prima! Dove le prende 9000byte?

Altra prova se nella funzione anziché allocare dichiarando il vettore lo vado ad allocare dinamicamente con la malloc tutto funziona seconda la logica.

#include <FreeMemory.h>

#define LEN_VET 1024
#define LEN_VET2 300

byte vet1[LEN_VET];


void setup() {                  
  Serial.begin(19200); 
  
  Serial.println(freeMemory());
  
  for(int i=0;i<LEN_VET;i++) {
    vet1[i] = i;
  }  

  Serial.println(freeMemory());  
  gen();   
  Serial.println(freeMemory());    
}

// the loop routine runs over and over again forever:
void loop() {        //... 
}
void gen()
{
    byte *vet2;
    //byte vet2[LEN_VET2];    
    vet2 = (byte *) malloc(LEN_VET2 * sizeof(byte));
     
           
     for(int i=0;i<LEN_VET2;i++) {
        vet2[i] = 100;
        //Serial.println(vet2[i]);
     } 
     Serial.println(freeMemory());
   
   free(vet2);  
}

Risultato:

810
810
504
810

il che è giusto.

due cose:
-te stai dichiarando un vettore,lo riempi e non usi i valori..forse ti sega anche questo(se compilasse con l'opzoine -O3 nn me ne stupirei)
-sulla malloc con 9000 bisogna considerare che a volte può fallire..solitamente in questo caso ritorna NULL..ma se te non fai controlli del tipo puntatoreRitornato!=NULL,potresti andare a scrivere in qlk area di memoria..quindi andresti a scrivere dall'indirizzo 0 in poi..e dato che usi un'architettura harvard,non rischi di sovrascivere il codice,ma solo i dati..quindi non ti pianti subito..

m_ri:
due cose:
-te stai dichiarando un vettore,lo riempi e non usi i valori..forse ti sega anche questo(se compilasse con l'opzoine -O3 nn me ne stupirei)
-sulla malloc con 9000 bisogna considerare che a volte può fallire..solitamente in questo caso ritorna NULL..ma se te non fai controlli del tipo puntatoreRitornato!=NULL,potresti andare a scrivere in qlk area di memoria..quindi andresti a scrivere dall'indirizzo 0 in poi..e dato che usi un'architettura harvard,non rischi di sovrascivere il codice,ma solo i dati..quindi non ti pianti subito..

Nel codice che ho postato la print del valore del vettore è commentata ma ho provato anche a stampare il valore quindi ci accedo e lo uso.

Per quanto riguarda l'esempio dei 9000byte non ho usato il codice della malloc ma quello in cui dichiaro il vettore come variabile nella funzione e oltre a scriverci dentro stampo anche i singoli valori, com'è possibile?

uhmmm posta il codice della liibreria che usi

la versione base per lo spazio ram è questa:

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

questa funzione dovrebbe solo cotare la distanza tra stack e heap, dove l'inizio dello stack viene considerata l'indirizzo di int v.

in realtà all'interno dello heap possono essere presenti blocchi di memoria che sono stati liberati con una free, e che vengono così contati:

/* 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;
}

in teoria quando allochi qualcosa con la malloc, dovresti vedere il valore restituito da freeListSize cambiare, ed eventualmente anche quellod di __brkval se nella lista della ram freeata non c'era abbastanza spazio.

Invece per le variabili dichiarate localmente e senza uso di malloc, dovresti vedere l'indirizzo dello stack cambiare.

per capire cosa realmente sta succedendo, ti consiglio di stampare gli indirizzi delle funzioni, degli array e anche delle variabili locali. così capiamo dove sta il problema.

lesto:
uhmmm posta il codice della liibreria che usi

la libreria è questa Arduino Playground - AvailableMemory

per capire cosa realmente sta succedendo, ti consiglio di stampare gli indirizzi delle funzioni, degli array e anche delle variabili locali. così capiamo dove sta il problema.

ho fatto cosi e in effetti ho visto che, se il vet2 viene creato come un "normale" vettore il ciclo for(...) assegna e stampa il vet2, anche se questo supera di gran lunga la memoria disponibile non si fa scrupoli a sovrascrivere gli stessi indirizzi, tutto cambia se alloco memoria al vettore con malloc, perché se supero la memoria disponibile ho un blocco del programma appena parte, diversamente quando ho spazio libero la freeMemory() ritorna i giusti valori.

Ho avuto lo stesso comportamento della malloc chiamando alla fine della funzione free(vet2).

grazie per l'aiuto

in teoria il caso della creazione dell'array normale dovrebbe crashare il programma, ed invece la malloc non crasha il programma in se, ma probabilmente lo fa il fatto che usi il valore NULL che ti restituisce come se fosse un vettore.

come ho già detto prima,dopo aver fatto la malloc controlla il puntatore: se è NULL,stampi "allocazione fallita" ed esci,altrimenti continui..in questo modo non dovrebbe crashare..

x iscrizione