Data Alignment

CPU는 byte단위로 data를 읽는 것이 아니라 word단위로 data를 메모리에서 읽어들인다. 
예를 들어 x86의 경우 32비트(4바이트)단위로 data를 읽어들이는데 이는 즉 0x0에서 0x3까지 4바이트를 읽어들이는 것은 한 번에 데이터를 읽어들일 수 있지만 0x1부터 0x4까지 4바이트를 읽어들이려면 0x0 ~ 0x3 , 0x4 ~ 0x7 이렇게 총 2 번 메모리를 읽어들여야 한다.
이러한 데이터를 비정렬 데이터라고 하는데 만약 비정렬 데이터를 들어들이려고 할 때 cpu의 동작은 cpu마다 다르다.
예를 들어, x86이나 x64같은 경우 cpu는 기본적으로 메모리 상에서 비정렬된 데이터에 대한 읽기 작업을 2개의 정렬된 위치에서의 읽기 작업으로 전환해서 수행한다. 즉 성능이 매우 안좋아지는 것이다. 하지만 예외가 발생하지는 않는다. 그러나 IA-64같은 경우는 비정렬 데이터에 접근하려고 하면 비정렬 예외가 발생하고 OS가 그 예외를 자동으로 처리해주거나 소프트웨어에 예외가 전달되게 된다.
그러면 x86기반에서 visual C++을 이용해 구조체를 사용하면 double같은 경우 8-byte로 alignment가 된다. 이는 왜 그런걸까?
double(8-byte type)을 4-byte alignment하든 8-byte alignment하든 cpu는 2번 메모리에서 읽어들여야하는데 말이다.
그 이유는 바로 캐시라인 때문이다. 캐시라인의 크기는 cpu마다 다른데 Intel x86 cpu의 경우 cache line의 크기는 64byte이다. 만약에 double이 4-byte alignment된다고 가정하자. 그러면 double variable이 0x3C ~ 0x43에 위치하고, cache line 1이 0x0 ~ 0x3F , cache line 2가 0x40 ~ 0x7F 의 메모리 주소의 data를 가지고 있다고 생각해보자. 이 경우 double variable의 data를 읽으려면 cache line 1과 cache line 2를 둘 다 읽어들여야한다. 즉 cache line에 의해 값이 쪼개질 수 있는 것이다. 따라서 double type의 variable은 8-byte alignment되어야 효율적인 것이다. alignment는 2^N의 형태로 alignment되는 것이 좋다고 여겨지고 2^N의 값은 최대 cache line의 크기로 하는 것이 좋다고 생각된다.
위 링크는 64-bit intel architecture manual에서 data alignment에 대해 언급된 부분이다.
위 링크는 왜 c에서 double이 8-bytes alignment 되는 지에 대한 스택오버플로우 질문이다.
위 링크는 정렬된 , 비정렬된 메모리 access에 따른 성능을 다루고있다. 결과를 보면 2배 차이나는 것을 알 수 있다.

댓글