[C] tagged pointer - 포인터에 정보 담기

Tagged pointer는 메모리 크기를 줄이기 위한 고전적인 테크닉이다. 기본적인 아이디어는 포인터의 모든 값이 의미 있는 값은 아니라는 것이다. 예를 들어 4 byte 단위로 align 되는 객체의 32-bit 포인터를 생각해보자. 그렇다면 이 객체의 주소는 4로 나누어 떨어지는 값이 돼야 하니 LSB(Least Significant Bit)으로 부터 2 bit은 언제나 0b00으로 고정될 것이다. 그렇다면 이 2 bit을 다른 정보를 담는 데 써도 아무 문제가 없다. 조금 더 구체적으로 경우 포인터의 값이 0x5678FFF0, 0x5678FFF1, 0x5678FFF2, 0x5678FFF3인 경우 모두 0x5678FFF0에 있는 객체를 가리키도록 하고, 0x5678FFF4, 0x5678FFF5, 0x5678FFF6, 0x5678FFF7인 경우 모두 0x5678FFF4를 가리키는 포인터로 해석하는 것이다.

Tagged pointer를 만드는데 LSB 만 쓸 수 있는 건 아니다. 보통 user space에서 쓸 수 있는 최대 메모리가 제한돼 있다. 예를 들어 32-bit 윈도우에서 user space는 최대 3GB 까지 늘릴 수 있지만, 기본적으로 2GB이다. 즉, MSB(Most Significant Bit) 1 bit를 tag에 쓸 수 있다. 64-bit 리눅스라면, 프로세스당 최대 메모리 스페이스는 256 TB까지 이므로 48 bit만 사용된다. 즉, MSB로부터 16 bit를 tag에 사용할 수 있다. 하지만 위의 두 예시에서 보았듯이 tag에 이용할 수 있는 MSB의 크기는 시스템별로 다르다. 따라서 MSB를 tagged pointer로 사용하는 경우 portable 한 코드를 만들기 어려워진다.

Tagged pointer를 모든 포인터에 일반적으로 적용하지 않아도 된다. 그보다는 테이블같은 것에 저장할 포인터에만 사용하거나 포인터를 리턴하는 함수에 대해서만 사용하는 것이 일반적이다. 특히 포인터와 추가 정보를 리턴하는 함수를 tagged pointer를 리턴하는 함수로 만들면, 리턴값이 하나의 레지스터에 들어가게 돼서 더 빨라지기도 한다.

Tagged pointer는 사용하기 불편한 테크닉이지만 놀랍게도 아직 종종 사용된다. 하지만 사용하기 전에 정말로 필요한지 고민해봐야 한다. Tagged pointer는 사용하는 메모리 크기를 줄이지만, 구현이 쓸데없이 복잡해진다. 구현이 복잡하다는 것은 버그가 발생할 확률이 높다는 것이고, 게다가 디버거는 tagged pointer의 의미를 알지 못 하므로 디버깅도 많이 귀찮아진다. 이 개발 비용을 감수하면서도 tagged pointer가 주는 이득이 충분한지 따져보고 사용해야 한다.

댓글

이 블로그의 인기 게시물

USB 2.0 케이블의 내부 구조

[C++] enum class - 안전하고 쓰기 쉬운 enum

Log Aggregator 비교 - Scribe, Flume, Fluentd, logstash

[Web] SpeechSynthesis - TTS API

[Python] cache 데코레이터로 최적화하기