Ottimizzare C++/Scrivere codice C++ efficiente/Allocazioni e deallocazioni

Wikibooks, manuali e libri di testo liberi.
Ottimizzare C++
modifica
CopertinaOttimizzare C++/Copertina
  1. IntroduzioneOttimizzare C++/Introduzione
  2. Ciclo di vita dell’ottimizzazioneOttimizzare C++/Ciclo di vita dell’ottimizzazione
  3. Scrivere codice C++ efficienteOttimizzare C++/Scrivere codice C++ efficiente
    1. Costrutti che migliorano le prestazioniOttimizzare C++/Scrivere codice C++ efficiente/Costrutti che migliorano le prestazioni
    2. Costrutti che peggiorano le prestazioniOttimizzare C++/Scrivere codice C++ efficiente/Costrutti che peggiorano le prestazioni
    3. Costruzioni e distruzioniOttimizzare C++/Scrivere codice C++ efficiente/Costruzioni e distruzioni
    4. Allocazioni e deallocazioniOttimizzare C++/Scrivere codice C++ efficiente/Allocazioni e deallocazioni
    5. Accesso alla memoriaOttimizzare C++/Scrivere codice C++ efficiente/Accesso alla memoria
    6. Uso dei threadOttimizzare C++/Scrivere codice C++ efficiente/Uso dei thread
  4. Tecniche generali di ottimizzazioneOttimizzare C++/Tecniche generali di ottimizzazione
    1. Input/OutputOttimizzare C++/Tecniche generali di ottimizzazione/Input/Output
    2. CachingOttimizzare C++/Tecniche generali di ottimizzazione/Caching
    3. OrdinamentoOttimizzare C++/Tecniche generali di ottimizzazione/Ordinamento
    4. Altre tecnicheOttimizzare C++/Tecniche generali di ottimizzazione/Altre tecniche
  5. Ottimizzazione del codice C++Ottimizzare C++/Ottimizzazione del codice C++
    1. Allocazione e deallocazioneOttimizzare C++/Ottimizzazione del codice C++/Allocazione e deallocazione
    2. Supporto run-timeOttimizzare C++/Ottimizzazione del codice C++/Supporto run-time
    3. Numero di istruzioniOttimizzare C++/Ottimizzazione del codice C++/Numero di istruzioni
    4. Costruzioni e distruzioniOttimizzare C++/Ottimizzazione del codice C++/Costruzioni e distruzioni
    5. PipelineOttimizzare C++/Ottimizzazione del codice C++/Pipeline
    6. Accesso alla memoriaOttimizzare C++/Ottimizzazione del codice C++/Accesso alla memoria
    7. Operazioni velociOttimizzare C++/Ottimizzazione del codice C++/Operazioni veloci

L'allocazione e la deallocazione dinamiche di memoria sono operazioni molto lente, a confronto dell'allocazione e della deallocazione automatiche di memoria. In altre parole, lo heap è molto più lento dello stack.

Inoltre, tale tipo di allocazione comporta uno spreco di spazio per ogni allocazione, genera frammentazione della memoria virtuale, e produce una scarsa località dei dati, con conseguente scadente utilizzo sia delle cache dei dati del processore che dello spazio di memoria virtuale.

L'allocazione/deallocazione dinamica di memoria veniva fatta in linguaggio C usando le funzioni malloc e free della libreria standard. In C++, pur essendo ancora disponibili tali funzioni, normalmente a tale scopo si usano gli operatori new, new[], delete, e delete[].

Ovviamente, un modo di ridurre le allocazioni è ridurre il numero di oggetti costruiti, e quindi la sezione "Costruzioni e distruzioni" di questo capitolo serve indirettamente anche allo scopo di questa sezione.

Tuttavia, qui si presenteranno linee-guida per ridurre il numero di allocazioni di memoria per un dato numero di chiamate all'operatore new.

Array di lunghezza fissa[modifica]

Se un array statico o non grande ha lunghezza costante, invece di usare un oggetto vector, usa un array del C, o un oggetto array della libreria Boost.

I vector memorizzano i dati in un buffer allocato dinamicamente, mentre le altre soluzioni proposte allocano i dati nell'oggetto stesso. Questo consente di evitare allocazioni/deallocazioni di memoria dinamica e di favorire la località dei dati.

Se l'array è grande, tali vantaggi diminuiscono, e invece risulta più importante evitare di usare troppo spazio sullo stack.

Allocatore a blocchi[modifica]

Se devi allocare numerosi blocchi di memoria della stessa dimensione, assicurati di usare un allocatore a blocchi.

Un allocatore a blocchi (detto anche allocatore a pool) alloca blocchi di memoria medi o grandi, e fornisce servizi di allocazione/deallocazione di blocchi più piccoli di dimensione costante. Offre alta velocità di allocazione/deallocazione, bassa frammentazione della memoria, uso efficiente delle cache dei dati e della memoria virtuale.

In particolare, un allocatore di questo tipo migliora notevolmente le prestazioni dei contenitori std::list, std::set, std::multi_set, std::map, e std::multi_map.

Se la tua implementazione della libreria standard non usa già un allocatore a blocchi per questi contenitori, dovresti procurartene uno (per esempio, questo: http://www.codeproject.com/KB/stl/blockallocator.aspx), e specificarlo come parametro di template per le istanze di tali template di contenitori.

Aggiunta di elementi a collezione[modifica]

Quando aggiungi elementi in fondo a una collezione, usa push_back per aggiungere un singolo elemento, usa insert per aggiungere una sequenza, e usa back_inserter per fare in modo che un algoritmo STL aggiunga elementi a una sequenza.

La funzione push_back garantisce un tempo lineare ammortizzato, in quanto, nel caso dei vector, ingrandisce esponenzialmente la capacità.

La classe back_inserter chiama internamente la funzione push_back.

La funzione insert permette di inserire in modo ottimizzato un'intera sequenza, e quindi una sola chiamata di questo tipo è più veloce di numerose chiamate a push_back.