Semplice implementazione C per tenere traccia di malloc / free?

linguaggio di programmazione: piattaforma C: ARM Compiler: ADS 1.2

Ho bisogno di tenere traccia delle semplici chiamate melloc/free gratuite nel mio progetto. Ho solo bisogno di avere un’idea di base di quanta memoria heap è necessaria quando il programma ha allocato tutte le sue risorse. Pertanto, ho fornito un wrapper per le chiamate malloc/free gratuite. In questi wrapper ho bisogno di incrementare un conteggio di memoria corrente quando viene chiamato malloc e lo decremento quando viene chiamato free . Il caso malloc è semplice perché ho le dimensioni da allocare dal chiamante. Mi chiedo come gestire il caso free quanto ho bisogno di memorizzare il puntatore / mapping delle dimensioni da qualche parte. Essendo C, non ho una mappa standard per implementarlo facilmente.

Sto cercando di evitare il collegamento in qualsiasi libreria quindi preferire l’implementazione * .c / h.

Quindi mi chiedo se ci sia già una semplice implementazione a cui potrei portarmi. In caso contrario, questa è la motivazione per procedere e implementarne uno.

EDIT: puramente per il debug e questo codice non viene spedito con il prodotto.

EDIT: implementazione iniziale basata sulla risposta di Makis. Apprezzerei il feedback su questo.

EDIT: Reworked implementation

 #include  #include  #include  #include  #include  static size_t gnCurrentMemory = 0; static size_t gnPeakMemory = 0; void *MemAlloc (size_t nSize) { void *pMem = malloc(sizeof(size_t) + nSize); if (pMem) { size_t *pSize = (size_t *)pMem; memcpy(pSize, &nSize, sizeof(nSize)); gnCurrentMemory += nSize; if (gnCurrentMemory > gnPeakMemory) { gnPeakMemory = gnCurrentMemory; } printf("PMemAlloc (%#X) - Size (%d), Current (%d), Peak (%d)\n", pSize + 1, nSize, gnCurrentMemory, gnPeakMemory); return(pSize + 1); } return NULL; } void MemFree (void *pMem) { if(pMem) { size_t *pSize = (size_t *)pMem; // Get the size --pSize; assert(gnCurrentMemory >= *pSize); printf("PMemFree (%#X) - Size (%d), Current (%d), Peak (%d)\n", pMem, *pSize, gnCurrentMemory, gnPeakMemory); gnCurrentMemory -= *pSize; free(pSize); } } #define BUFFERSIZE (1024*1024) typedef struct { bool flag; int buffer[BUFFERSIZE]; bool bools[BUFFERSIZE]; } sample_buffer; typedef struct { unsigned int whichbuffer; char ch; } buffer_info; int main(void) { unsigned int i; buffer_info *bufferinfo; sample_buffer *mybuffer; char *pCh; printf("Tesint MemAlloc - MemFree\n"); mybuffer = (sample_buffer *) MemAlloc(sizeof(sample_buffer)); if (mybuffer == NULL) { printf("ERROR ALLOCATING mybuffer\n"); return EXIT_FAILURE; } bufferinfo = (buffer_info *) MemAlloc(sizeof(buffer_info)); if (bufferinfo == NULL) { printf("ERROR ALLOCATING bufferinfo\n"); MemFree(mybuffer); return EXIT_FAILURE; } pCh = (char *)MemAlloc(sizeof(char)); printf("finished malloc\n"); // fill allocated memory with integers and read back some values for(i = 0; i buffer[i] = i; mybuffer->bools[i] = true; bufferinfo->whichbuffer = (unsigned int)(i/100); } MemFree(bufferinfo); MemFree(mybuffer); if(pCh) { MemFree(pCh); } return EXIT_SUCCESS; } 

Puoi allocare alcuni byte extra nel tuo wrapper e inserire un id (se vuoi essere in grado di accoppiare malloc () e free ()) o solo la dimensione lì. Basta malloc () che molta più memoria, memorizza le informazioni all’inizio del tuo blocco di memoria e sposta il puntatore indietro di molti byte in avanti.

Questo può, anche, essere facilmente utilizzato anche per puntatori recinti / impronte digitali e così via.

O puoi accedere alle tabelle interne usate da malloc / free (vedi questa domanda: Dove sono malloc () / free () Memorizza le dimensioni e gli indirizzi allocati? Per alcuni suggerimenti), oppure devi gestire le tue tabelle nei tuoi wrapper.

Puoi sempre usare valgrind invece di eseguire la tua implementazione. Se non ti interessa la quantità di memoria che hai allocato potresti usare un’implementazione ancora più semplice: (L’ho fatto molto velocemente in modo che potessero esserci degli errori e mi rendo conto che non è l’implementazione più efficiente. Il pAllocedStorage dovrebbe avere un dimensione iniziale e aumentare di un fattore per un ridimensionamento ecc. ma si ottiene l’idea).

EDIT: Ho perso che questo era per ARM, per quanto ne so Valgrind non è disponibile su ARM in modo che potrebbe non essere un’opzione.

 static size_t indexAllocedStorage = 0; static size_t *pAllocedStorage = NULL; static unsigned int free_calls = 0; static unsigned long long int total_mem_alloced = 0; void * my_malloc(size_t size){ size_t *temp; void *p = malloc(size); if(p == NULL){ fprintf(stderr,"my_malloc malloc failed, %s", strerror(errno)); exit(EXIT_FAILURE); } total_mem_alloced += size; temp = (size_t *)realloc(pAllocedStorage, (indexAllocedStorage+1) * sizeof(size_t)); if(temp == NULL){ fprintf(stderr,"my_malloc realloc failed, %s", strerror(errno)); exit(EXIT_FAILURE); } pAllocedStorage = temp; pAllocedStorage[indexAllocedStorage++] = (size_t)p; return p; } void my_free(void *p){ size_t i; int found = 0; for(i = 0; i < indexAllocedStorage; i++){ if(pAllocedStorage[i] == (size_t)p){ pAllocedStorage[i] = (size_t)NULL; found = 1; break; } } if(!found){ printf("Free Called on unknown\n"); } free_calls++; free(p); } void free_check(void) { size_t i; printf("checking freed memeory\n"); for(i = 0; i < indexAllocedStorage; i++){ if(pAllocedStorage[i] != (size_t)NULL){ printf( "Memory leak %X\n", (unsigned int)pAllocedStorage[i]); free((void *)pAllocedStorage[i]); } } free(pAllocedStorage); pAllocedStorage = NULL; } 

Vorrei usare rmalloc . È una semplice libreria (in realtà è solo due file) per il debug dell’utilizzo della memoria, ma ha anche il supporto per le statistiche. Dal momento che hai già funzioni wrapper dovrebbe essere molto facile usare rmalloc per questo. Ricorda che devi anche sostituire strdup, ecc.

Il tuo programma potrebbe anche aver bisogno di intercettare realloc (), calloc (), getcwd () (dato che può allocare memoria quando il buffer è NULL in alcune implementazioni) e forse strdup () o una funzione simile, se è supportato dal tuo compilatore

Se stai usando x86 potresti semplicemente eseguire il tuo binario con valgrind e raccogliere tutte queste informazioni per te, usando l’implementazione standard di malloc e free . Semplice.

Ho provato alcune delle stesse tecniche menzionate in questa pagina e sono finito qui da una ricerca su google. So che questa domanda è vecchia, ma volevo aggiungere per il record …

1) Il tuo sistema operativo non fornisce strumenti per vedere quanta memoria heap è in uso in un processo in esecuzione? Vedo che stai parlando di ARM, quindi potrebbe essere il caso. Nella maggior parte dei sistemi operativi completi, si tratta semplicemente di utilizzare uno strumento di cmd-line per vedere le dimensioni dell’heap.

2) Se disponibile nella tua libc, sbrk (0) sulla maggior parte delle piattaforms ti dirà l’indirizzo finale del tuo segmento di dati. Se ce l’hai, tutto ciò che devi fare è archiviare quell’indirizzo all’inizio del tuo programma (ad esempio, startBrk = sbrk (0)), quindi in qualsiasi momento la dimensione allocata è sbrk (0) – startBrk.

3) Se è ansible utilizzare oggetti condivisi, si sta collegando dynamicmente alla propria libc e il caricatore del runtime del sistema operativo ha qualcosa come una variabile di ambiente LD_PRELOAD, potrebbe essere più utile creare il proprio object condiviso che definisce le funzioni libc effettive con gli stessi simboli (malloc (), non MemAlloc ()), quindi il caricatore carica prima la lib e “interpone” le funzioni di libc. Puoi inoltre ottenere gli indirizzi delle funzioni libc effettive con dlsym () e il flag RTLD_NEXT in modo che tu possa fare ciò che stai facendo sopra senza dover ricompilare tutto il tuo codice per usare i tuoi malloc / free wrappers. È quindi solo una decisione di runtime quando si avvia il programma (o qualsiasi programma che si adatta alla descrizione nella prima frase) in cui si imposta una variabile di ambiente come LD_PRELOAD = mymemdebug.so e quindi eseguita. (google per l’interposizione di oggetti condivisi .. è una tecnica eccezionale e utilizzata da molti debugger / profiler)