원문 출처 : http://soen.kr/lecture/ccpp/cpp2/18-1-5.htm



첫 번째로 구조체가 시작될 번지(base)를 고를 때 가급적이면 16바이트 경계에서 시작하도록 한다. 왜냐하면 최신 CPU들은 속도 증가를 위해 캐시를 사용하는데 캐시의 단위가 16바이트로 되어 있기 때문이다. 캐시 크기의 배수 위치에 구조체를 배치하면 이 구조체를 자주 액세스할 때 캐시 용량을 덜 차지하면서도 빠르게 액세스할 수 있다. 만약 16바이트 경계의 양쪽에 걸치게 되면 캐시도 많이 차지할 뿐더러 액세스 속도도 느려질 것이다.

두 번째로 구조체의 멤버를 배치할 때 멤버의 오프셋도 액세스하기 유리한 위치로 조정한다. 별다른 지정이 없으면 멤버의 크기에 따라 자연스러운 경계 위치에 맞추도록 되어 있는데 예를 들어 int는 4바이트, double은 8바이트 경계에 맞춘다. 그래서 위 예제의 경우 c가 1바이트를 차지하고 난 후 d는 다음 8바이트 경계에 배치되므로 c와 d사이에 7바이트는 버려지고 사용되지 않는다. 이렇게 사용되지 않고 버려지는 공간을 패딩(Padding) 이라고 한다.



컴파일러는 CPU가 메모리를 최대한 빠른 속도로 액세스할 수 있도록 구조체의 베이스와 멤버의 오프셋을 조정해서 배치하는데 이를 구조체의 정렬(alignment)이라고 한다. 자료를 크기순으로 나열하는 정렬(Sort)과는 번역만 같으며 뜻은 다르다. 개발자들은 일반적으로 구조체의 정렬 방식에 대해 몰라도 별 문제가 없다. 왜냐하면 변수가 어떤 메모리에 배치되는가는 원칙적으로 컴파일러 마음이며 개발자는 변수명으로 그 번지의 내용을 읽고 쓰기 때문이다. 또한 멤버의 오프셋이 어떻게 설정되든간에 코드에서는 st1.c, st1.d 연산문으로 멤버를 액세스할 수 있으며 . 연산자는 컴파일러가 정한 오프셋을 정확하게 찾아 준다.

구조체의 정렬 기능에 의해 액세스 속도는 빨라지지만 효율을 위해 버려지는 메모리가 있다는 점이 다소 안타까워 보일 것이다. 그러나 위의 tag_st1은 이런 효과를 극대화해서 보여주기 위해 1바이트 멤버 다음에 8바이트 멤버를 의도적으로 배치했을 뿐이지 현실적으로 구조체의 멤버들은 대부분 int, unsigned, char [ ] 등이기 때문에 걱정하는 것만큼 메모리가 낭비되지는 않는다.

+ Recent posts