Programmer

Memory Alignment의 필요성

Memory Alignment(메모리 정렬)는 왜 필요할까?

자, 32비트 CPU에서 4-byte 데이터가 4의 배수가 아닌 주소에 존재한다고 생각해보자.
아래와 같이 데이터가 4-byte의 경계에 걸쳐있다.
이 데이터를 읽으려면 어떻게 해야할까?

0  1  2  3  4  5  6  7  8 = address
|-----------|-----------|
|  |  |00|F4|14|1F|  |  | = data
|-----------|-----------|

CPU는 워드 사이즈로 워드 사이즈의 배수인 주소만 읽기가 가능하다.
그래서 이렇게 되면 CPU는 0-3 범위의 데이터를 한번 읽고,
4-7 범위를 한번 더 읽은 뒤 합쳐야 한다.
즉 한번에 읽을 수 없어서 추가적인 과정이 필요하다.
캐시라인이나 페이지경계에 걸쳐 있다면 문제가 생기기도 한다.

x86 같은 아키텍쳐는 이런 정렬되진 않은 데이터도 읽은 뒤 합쳐주지만,
GPU나 RISC계열 CPU는 대부분 이를 지원하지 않아 bus-error를 낸다.

여기까지가 일반적인 설명인데,
“그래서 왜 CPU는 꼭 워드 사이즈 경계로만 데이터를 읽는가?”

32비트 CPU가 하나 있다고 생각해보자.
CPU가 메모리에서 load하기 위해선 IR를 다음과 같이 세팅한다.

1000 0000 0000 0000 0000 0000 0000 0000
||
|└-> 0 : R0
|    1 : R1
|
└--> 0 : STORE
     1 : LOAD
  1. 0번 비트는 메모리에 store를 하는지, load를 하는지 지정한다.
  2. 1번 비트는 어떤 레지스터의 내용을 store 할지,
    어떤 레지스터에 내용을 load 해올지 지정한다.
  3. 나머지 30개의 비트는 가져올 메모리의 주소를 표현한다.

그런데 어라, 주소를 표현할 수 있는 비트가 30개 밖에 안된다.
30비트로 32비트를 표현해야 하는데 어떻게 하면 될까.
30비트가 나타내는 주소의 단위가 4바이트가 되도록 하면 된다.
그러면 표현할 수 있는 주소가 4배 늘어나므로 30비트로 32비트를 표현할 수 있다.

┌-------------30 bit----------------┐
???? ???? ???? ???? ???? ???? ???? ??00

최하위 비트 2개가 무조건 0이라고 지정하면
4의 배수만 표현이 가능하지만
위에서 얘기한대로 30비트로 32비트의 범위를 표현가능해진다.

(오해할 수 있는데, CPU에서 포인터 주소연산 할 때에는 여전히 1바이트 단위이다.
CPU에서 메모리에 요청할 때 4바이트 단위로 요청해 가져와서 따로 후처리를 한다는 것이다.)


위와 같은 이유들로 메모리 정렬이 필요한 것이다.
(이유 중 하나 일 뿐이지, 많은 CPU가 이 방식을 사용하는 것은 아니다.)