Ottimizzare C++/Scrivere codice C++ efficiente/Allocazioni e deallocazioni: differenze tra le versioni
m Bot: Sostituzione automatica (-[[Categoria:Ottimizzare C++|Ottimizzare C++/Scrivere codice C++ efficiente/ +[[Categoria:Ottimizzare C++|) |
Nessun oggetto della modifica |
||
Riga 5: | Riga 5: | ||
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 della CPU che della memoria virtuale. |
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 della CPU che della memoria virtuale. |
||
Tale allocazione/deallocazione in linguaggio C |
Tale allocazione/deallocazione veniva fatta in linguaggio C con le funzioni <code>malloc</code> e <code>free</code>. |
||
In C++, pur essendo ancora disponibili tali funzioni, normalmente a tale scopo si usano gli operatori <code>new</code>, <code>new[]</code>, <code>delete</code>, e <code>delete[]</code>. |
|||
Ovviamente, un modo di ridurre le allocazioni è ridurre il numero di oggetti costruiti, e quindi la sezione |
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 |
Tuttavia, qui si presenteranno linee-guida per ridurre il numero di allocazioni di memoria per un dato numero di chiamate all'operatore <code>new</code>. |
||
=== Array di lunghezza fissa === |
=== Array di lunghezza fissa === |
||
'''Se un array statico o non grande ha lunghezza costante, non usare un oggetto <code>vector</code>, ma usa un array del C, o un oggetto <code> |
'''Se un array statico o non grande ha lunghezza costante, non usare un oggetto <code>vector</code>, ma usa un array del C, o un oggetto <code>array</code> della libreria [http://www.boost.org Boost].''' |
||
I vector memorizzano i dati in un buffer allocato dinamicamente, mentre le altre soluzioni proposte allocano i dati nell'oggetto stesso. |
I <code>vector</code> 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. |
Questo consente di evitare allocazioni/deallocazioni di memoria dinamica e di favorire la località dei dati. |
||
Riga 24: | Riga 25: | ||
'''Se devi allocare numerosi blocchi di memoria della stessa dimensione, assicurati di usare un allocatore a blocchi.''' |
'''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, offrendo alta velocità di allocazione/deallocazione, bassa frammentazione della memoria, uso efficiente delle cache dei dati e della memoria virtuale. |
Un [[w:en:Memory pool|''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, offrendo 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 <code>std::list</code>, <code>std::set</code>, <code>std::multi_set</code>, <code>std::map</code>, e <code>std::multi_map</code>. |
In particolare, un allocatore di questo tipo migliora notevolmente le prestazioni dei contenitori <code>std::list</code>, <code>std::set</code>, <code>std::multi_set</code>, <code>std::map</code>, e <code>std::multi_map</code>. |
||
Riga 32: | Riga 33: | ||
=== Aggiunta di elementi a collezione === |
=== Aggiunta di elementi a collezione === |
||
''' |
'''Quando aggiungi elementi in fondo a una collezione, usa <code>push_back</code> per aggiungere un singolo elemento, usa <code>insert</code> per aggiungere una sequenza, e usa <code>back_inserter</code> per fare in modo che un algoritmo STL aggiunga elementi a una sequenza.''' |
||
La funzione <code>push_back</code> garantisce un tempo lineare ammortizzato, in quanto, nel caso del <code>vector</code>, ingrandisce esponenzialmente la capacità. |
La funzione <code>push_back</code> garantisce un tempo lineare ammortizzato, in quanto, nel caso del <code>vector</code>, ingrandisce esponenzialmente la capacità. |
||
Riga 38: | Riga 39: | ||
La classe <code>back_inserter</code> chiama internamente la funzione <code>push_back</code>. |
La classe <code>back_inserter</code> chiama internamente la funzione <code>push_back</code>. |
||
La funzione <code>insert</code> permette di inserire in modo ottimizzato un'intera sequenza, e quindi una chiamata di questo tipo è più veloce di numerose chiamate a <code>push_back</code>. |
La funzione <code>insert</code> permette di inserire in modo ottimizzato un'intera sequenza, e quindi una sola chiamata di questo tipo è più veloce di numerose chiamate a <code>push_back</code>. |
||
[[Categoria:Ottimizzare C++|Allocazioni e deallocazioni]] |
[[Categoria:Ottimizzare C++|Allocazioni e deallocazioni]] |
||
{{Avanzamento| |
{{Avanzamento|100%|25 maggio 2008}} |
Versione delle 10:50, 25 mag 2008
L'allocazione e la deallocazione di memoria dinamica sono operazioni molto lente, se confrontate con l’allocazione e la deallocazione di memoria automatica, cioè su 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 della CPU che della memoria virtuale.
Tale allocazione/deallocazione veniva fatta in linguaggio C con le funzioni malloc
e free
.
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
Se un array statico o non grande ha lunghezza costante, non usare un oggetto vector
, ma 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 è medio o grande, tali vantaggi diminuiscono, e invece risulta più importante evitare di usare troppo spazio sullo stack.
Allocatore a blocchi
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, offrendo 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
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 del 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
.