가끔 성능 최적화를 위해 혹은 동작 자체를 위해 aligned된 memory를 할당 할 필요가 있다. 대표적으로
캐시 성능. 캐시 entry에 딱 맞는 데이터인데 alignment가 안 맞춰져 있으면 두 개의 캐시 entry를 써야 하는 불상사가 생길 수 있다. 용량도 낭비지만, 캐시 miss가 한 번 더 생긴다는 면에서 문제가 있음. 이 문제를 aligned 메모리 할당으로 해결할 수 있다.
unaligned access가 안되는 시스템. unaligned access를 허용하지 않는 경우가 생기는 이유를 하드웨어 관점에서 설명한 글. 쟁점은 Unaligned Memory Access Example에서 나오는데, 메모리 버스로 인해 제약된 word 크기에 대한 read/write 작업을 처리하는 것이 single cycle에 불가능한 경우가 생기기 때문. 자동으로 여러 operation으로 나눠서 접근하는 방식도 있지만 이 경우 접근을 2번 해야 해서 효율적이지 않기 때문에 그 경우를 미연에 방지하기 위해 이런 디자인을 택하는 경우가 있다.
page 하나에 들어갈 대형 자료 구조. page swapping에서 유리한 고지를 차지할 수 있다.
사실 malloc
도 alignment을 맞춰준다. 컴퓨터에서 사용하고 있는 primitive type의 크기에서 모두 사용할 수 있는 alignment에 맞추는데 보통 8byte다. 다만 이게 위의 모든 경우를 고려하는 alignmnet가 아니어서 alignment를 맞추는 memory allocator이 필요하다. 이를 block memory allocator이라고도 한다.
George Li께서 직접 만든 aligned malloc이 있다. 밑의 그림도 해당 레포지토리에서 가져온 것이니 참고 바란다. 코드는 직접 들어가서 확인하길 권유한다.
해당 함수를 보면 required
와 alignment
가 있는데, 전자는 저장하려는 데이터의 크기고 후자는 alignment
의 기준이 되는 byte다.
그러면 내부에서는 N+P+(A-1)
byte를 할당을 한다. N
이야 데이터 저장을 위해 할당을 하는 것이고, 왜 P + (A-1)
의 할당을 하는지가 중요하다.
시작 전에 몇 가지 가정을 하겠다. 먼저 A
는 2의 제곱수여야 한다. 하드웨어적 이유로 2의 제곱수가 아닌 alignment는 의미가 없으니 무리수인 가정은 아니다. 이해가 안되면 앞서 소개한 링크 글을 읽어보자.
그리고 A
가 0이 아니라고 가정하자. 사실 논리적으로 문제가 되진 않지만 할당이 고장날 수 있어서 이 가정을 하겠다.
malloc
이 N+P+(A-1)
크기의 아무 주소를 반환했다고 해보자.
앞에서
malloc
이 시스템 alignment를 지키면서 할당한다고 했지만 위가 그 경우를 포함하니 무시하자.
사실 그 반환 값이 alignment에 맞으면 좋겠지만, 아닌 경우가 대부분이다. 위의 경우 (십진수로) 65의 주소를 반환했다.
A
alignment에 맞으려면, A
가 1인 bit의 하위 bit들이 전부 0이 되어야 한다. 이 때문에 3번에서 A-1
과 &
를 해가지고 aligned 주소값을 구하는 것이다.
그러면 왜 A-1
과 P
를 추가로 할당하는가? 먼저 A-1
은 패딩용 byte다. 만약 2byte 데이터를 할당 하는데 4byte 패딩이 필요하다고 해보자. 2byte만 할당을 하고 그 주소가 65라면 65~66만 우리가 사용이 가능한 영역이다. 여기서 4byte alignment를 하는 것은 불가능하다. 4byte alignment를 시도할 유효 주소가 없기 때문. 그 주소를 언제나 보장받기 위해 A-1
을 사용한다.
이 값보다 작으면 alignment에 딱 맞는 주소랑 딱 1차이의 주소에 할당 된 경우 alignment를 못 맞춘다. 그리고 A
를 할당할 필요가 없는 이유는, 거기서부터는 커버 하는 범위가 alignment
랑 딱 맞는 주소, 혹은 더 널널한 경우를 할당하는 경우기 때문이다.
그러면 P
는 왜 할당하는 것일까? 나중에 free
호출 시 실제로 malloc
에서 할당한 주소값을 저장할 위치가 필요하기 때문이다. align 된 주소를 free
에 전달하면 오류를 일으키기 때문.
posix_memalign
aligned memory allocator은 C의 standard library에서 제공해준다. glibc 2.1.91부터는 posix_memalign
을 쓰는 것이 권장되며, stdlib.h
에 헤더가 있다.
사용 방법은 간단하다. aligned memory를 가리키는 pointer을 가리킬 pointer인 memptr
, 할당 size
, alignment
를 전달하면 된다. 유의점은
alignment
는 void *
의 배수여야 하고 2의 제곱수여야 한다.size
는 0이 아닌 것이 권장된다. 0이면 NULL을 반환할수도, free
에 전달 가능한 포인터가 반환될 수도 있다.성공시 0 반환, 실패시 error value 반환. errno
설정은 안 한다.
받은 pointer은 일반 free
로 반환이 가능하다.
memptr
은void **
임을 확인할 수 있는데, 이유는 그저return value
랑 별개로 pointer을 전달하기 위해서라고 한다. NULL 반환 등의 경우에서 생기는 ambiguity 문제를 해결하기 위해서다.