Buona domanda. Considerare questo tipo ipotetico:
struct A {
int n;
bool flag;
};
Quindi, un oggetto di tipo A
dovrebbe prendere cinque byte (quattro per l'int più uno per il bool), ma in realtà ci vogliono otto. Perché?
La risposta è visto, se si utilizza il tipo in questo modo:
const size_t N = 100;
A a[N];
Se ogni A
erano solo cinque byte, quindi a[0]
sarebbe allineare ma a[1]
, a[2]
e la maggior parte degli altri elementi non sarebbe.
Ma perché l'allineamento è importante? Ci sono diversi motivi, tutti relativi all'hardware. Una ragione è che la memoria utilizzata di recente/frequentemente viene memorizzata nella cache nelle linee della cache sul silicio della CPU per un accesso rapido. Un oggetto allineato più piccolo di una riga della cache si adatta sempre a una singola riga (ma si vedano i commenti interessanti elencati di seguito), ma un oggetto non allineato può essere a cavallo di due righe, sprecando la cache.
In realtà ci sono ancora più motivi hardware fondamentali, che riguardano il modo in cui i dati indirizzabili in byte vengono trasferiti lungo un bus dati a 32 o 64 bit, a parte le linee della cache. Non solo il disallineamento bloccherà il bus con ulteriori recuperi (dovuti come prima a cavalcare), ma costringerà anche i registri a spostare i byte mentre entrano. Ancora peggio, il disallineamento tende a confondere la logica di ottimizzazione (almeno, il manuale di ottimizzazione di Intel dice che lo fa, anche se non ho alcuna conoscenza personale di quest'ultimo punto). Quindi, il disallineamento è molto negativo dal punto di vista delle prestazioni.
Di solito vale la pena di sprecare i byte di riempimento per questi motivi.
Aggiornamento: I commenti seguenti sono tutti utili. Li raccomando.
* Un oggetto allineato più piccolo di una riga della cache si adatta sempre a una singola riga, ma un oggetto non allineato può essere a cavallo di due linee *> ** No **. Se allineato o meno un oggetto potrebbe trovarsi a cavallo di due linee. –
@MatthieuM., In realtà sì e no. Le dimensioni della linea di cache sono multipli della dimensione massima dei dati e di qualsiasi altro tipo fondamentale. Quindi tutti i tipi _native_ allineati (più, più) saranno naturalmente all'interno di una singola linea di cache. Si consideri che qualsiasi tipo allineato 1,2,4,8,16 byte verrà automaticamente allineato per adattarsi all'interno di una linea di cache di 64 o 128 byte. Un sistema sarebbe essenzialmente inutilizzabile se questo non fosse il caso. –
@ edA-qamort-ora-y: certo, ma un oggetto essendo un composto di tipi fondamentali potrebbe facilmente cavalcare due linee. Anche se è più piccolo. Supponendo una linea da 64 byte, posso avere un oggetto di 48 byte di grandi dimensioni, e in una tabella di tali oggetti, almeno uno su due si troverà a cavallo di due linee di cache. –