risorse | heap

heap

Introduzione

La libreria heap tiene traccia delle allocazioni di memoria effettuate segnalando, al termine del programma, se qualcuna di esse non è stata correttamente liberata.

La libreria nasce da un esercizio relativo all'overloading degli operatori globali new/delete. Le limitazioni dell'implementazione sono molteplici; in particolare:

La registrazione delle allocazioni di memoria viene effettuata dall'oggetto HeapTracer. Un'istanza di tale oggetto deve essere definita quanto prima, per assicurare il tracciamento di tutte le operazioni che coinvolgono la memoria dinamica. La dichiarazione di un'istanza globale dell'oggetto spesso è la soluzione migliore.

Le versioni overloaded degli operatori new/delete provvedono a notificare all'oggetto HeapTracer le avvenute (de)allocazioni di memoria. È responsabilità dell'oggetto HeapTracer mantenere traccia della sequenza di allocazioni e deallocazioni per poter, al termine del programma, verificare se esistono delle zone di memoria non deallocate.

Grazie all'uso di alcune macro (che d'altra parte costituiscono la ragione della mancata gestione dei placement new), di ogni allocazione viene registrata dimensione, provenienza (nome del file e linea sorgente) e tipologia (scalare/vettoriale):

#define new new(__FILE__, __LINE__)

// operatore new "standard" (librerie esterne)
void* operator new(size_t size);

// operatore new "custom" (librerie utente)
void* operator new (size_t size, const char* file, int line);

In corrispondenza di ogni deallocazione, l'oggetto HeapTracer verifica che la zona di memoria da liberare corrisponda ad una precedente allocazione, notificando in caso contrario un evento DoubleFree; verifica quindi la corrispondenza di tipo, emettendo eventualmente una notifica di tipo TypeMismatch. Se tutti i controlli hanno avuto esito positivo, procede con la deallocazione dell'area richiesta.

Uso della libreria

Per sottoporre una porzione di codice al controllo delle allocazioni è sufficiente includere il file Heap.h. Come regola generale si può assumere che la direttiva di inclusione va inserita nei soli file di implementazione (.cpp), a seguire tutti gli altri:

// file *.cpp
#include <...
#include <...

#ifdef DEBUG
#include <Heap.h>
#endif

La mancata gestione del placement new rende nella pratica obbligatoria, nei programmi che fanno uso della libreria STL (che ricorre spesso a questo tipo di allocazione), l'inclusione del file Heap.h dopo quelle relative ai file di STL.

L'allocazione dell'istanza dell'oggetto HeapTracer di norma avviene nel file di implementazione principale:

#ifdef DEBUG
Heap::HeapTracer theHeapTracer_;
#endif

int main ()
{

  // code

#ifdef DEBUG
  if (theHeapTracer_.GetQualifiedRequestCount () > 0)
  {
    theHeapTracer_.Dump (std::cerr, Heap::HeapRequest::e_qualified);
    std::cerr << "Memory leaks detected..." << std::endl;
  }
  else if (theHeapTracer_.GetUnqualifiedRequestCount () > 0)
    std::cerr << "Unqualified memory leaks detected..." << std::endl;
#endif

}

I file che costituiscono la libreria sono:

Note

Le allocazioni effettuate nei file non sottoposti al controllo di allocazione, così come quelle effettuate dalle liberie esterne - ed in genere ovunque la ridefinizione degli operatori non sia visibile - vengono registrate con provenienza "sconosciuta" e classificate come UnqualifiedRequest.

Poiché STL fa largo uso di oggetti statici le cui deallocazioni avvengono dopo la conclusione del programma, la presenza di richieste di allocazione non qualificate non viene segnalata come errore.

Pagina modificata il 15/11/2011