O subsistema de memória em um processador moderno é restrito ao acesso à memória na granularidade e alinhamento do tamanho da palavra; esse é o caso por várias razões.
Rapidez
Os processadores modernos têm vários níveis de memória cache nos quais os dados devem ser extraídos; o suporte a leituras de byte único faria com que a taxa de transferência do subsistema de memória estivesse fortemente ligada à taxa de transferência da unidade de execução (também conhecida como limite da CPU); tudo isso lembra como o modo PIO foi superado pelo DMA por muitos dos mesmos motivos nos discos rígidos.
A CPU sempre lê em seu tamanho de palavra (4 bytes em um processador de 32 bits); portanto, quando você acessa um endereço desalinhado - em um processador que a suporta -, o processador lê várias palavras. A CPU lerá cada palavra de memória que o endereço solicitado se encontra. Isso causa uma amplificação de até 2X o número de transações de memória necessárias para acessar os dados solicitados.
Por esse motivo, pode ser muito mais lento ler dois bytes que quatro. Por exemplo, digamos que você tenha uma estrutura na memória parecida com esta:
struct mystruct {
char c; // one byte
int i; // four bytes
short s; // two bytes
}
Em um processador de 32 bits, provavelmente seria alinhado como mostrado aqui:
O processador pode ler cada um desses membros em uma transação.
Digamos que você tenha uma versão compactada da estrutura, talvez da rede em que foi compactada para obter eficiência de transmissão; pode ser algo como isto:
Ler o primeiro byte será o mesmo.
Quando você solicita que o processador forneça 16 bits de 0x0005, ele precisará ler uma palavra de 0x0004 e deslocar para a esquerda 1 byte para colocá-lo em um registro de 16 bits; algum trabalho extra, mas a maioria pode lidar com isso em um ciclo.
Quando você pede 32 bits de 0x0001, obtém uma amplificação de 2X. O processador lerá de 0x0000 no registro de resultados e mudará 1 byte para a esquerda, depois lerá novamente de 0x0004 para um registro temporário, mudará para a direita 3 bytes e depois OR
com o registro de resultados.
Alcance
Para qualquer espaço de endereço especificado, se a arquitetura puder assumir que os 2 LSBs são sempre 0 (por exemplo, máquinas de 32 bits), poderá acessar 4 vezes mais memória (os 2 bits salvos podem representar 4 estados distintos) ou a mesma quantidade de memória com 2 bits para algo como bandeiras. Desativar os 2 LSBs de um endereço daria um alinhamento de 4 bytes; também conhecido como passo de 4 bytes. Cada vez que um endereço é incrementado, ele efetivamente incrementa o bit 2, e não o 0, ou seja, os últimos 2 bits sempre continuarão sendo 00
.
Isso pode até afetar o design físico do sistema. Se o barramento de endereço precisar de 2 bits a menos, pode haver 2 pinos a menos na CPU e 2 traços a menos na placa de circuito.
Atomicidade
A CPU pode operar atomicamente em uma palavra de memória alinhada, o que significa que nenhuma outra instrução pode interromper essa operação. Isso é fundamental para a operação correta de muitas estruturas de dados sem bloqueio e outros paradigmas de simultaneidade .
Conclusão
O sistema de memória de um processador é um pouco mais complexo e envolvido do que o descrito aqui; uma discussão sobre como um processador x86 realmente aborda a memória pode ajudar (muitos processadores funcionam de maneira semelhante).
Há muitos outros benefícios em aderir ao alinhamento de memória que você pode ler neste artigo da IBM .
O uso principal de um computador é transformar dados. As arquiteturas e tecnologias modernas de memória foram otimizadas ao longo de décadas para facilitar a obtenção de mais dados, entrada, saída e entre mais e mais unidades de execução mais rápidas - de uma maneira altamente confiável.
Bônus: caches
Outro alinhamento por desempenho que eu aludi anteriormente é o alinhamento em linhas de cache que são (por exemplo, em algumas CPUs) 64B.
Para obter mais informações sobre quanto desempenho pode ser obtido aproveitando os caches, consulte a Galeria de efeitos de cache do processador ; desta pergunta sobre tamanhos de linha de cache
O entendimento das linhas de cache pode ser importante para certos tipos de otimizações de programa. Por exemplo, o alinhamento de dados pode determinar se uma operação toca uma ou duas linhas de cache. Como vimos no exemplo acima, isso pode facilmente significar que, no caso desalinhado, a operação será duas vezes mais lenta.