C++/C++

C++ - SSO (Small String Optimization)

오의현 2024. 4. 11. 19:12

 

C++에서 문자열에 대해 알아보다 SSO라는 것을 알게 되었다.

SSO란, std::string 에서 길이가 짧은 문자열에 대한 최적화 방식이라고 한다.

 

기본적으로 string은 동적 메모리를 기반으로 문자열을 저장하게 된다.

동적 메모리를 기반으로 하게 되면 몇 가지 문제점이 생긴다.

 

1. 메모리의 할당과 해제 과정에서 오버헤드가 발생할 수 있다.

2. 힙영역의 데이터는 스택영역보다 데이터 처리 속도가 느리다. (특히 복사에서 두드러진다고 한다.)

더보기

힙 영역보다 왜 스택 영역이 빠른가에 대해서 좀 찾아봤는데, 이유야 여러가지가 있겠지만

스택영역의 경우 컴파일 과정에서 메모리의 주소를 어느정도 예측할 수 있기 때문에 계산된 주소를 이용해 바로바로 접근이 가능하기 때문에 힙영역보다 빠르다고 한다. 

 

이러한 문제점으로 인한 성능 저하를 최소화하기 위해, 적어도 길이가 짦은 문자열 만큼은 동적으로 메모리를 할당하지 말고 스택영역에 저장하자는 것이 SSO이다. 

일정 길이 이하의 문자열은 Stack영역에 저장하여, 오버헤드를 최소화 하겠다는 것이다.

 

실제로 시간을 재보았다.

std::chrono::system_clock::time_point Start = std::chrono::system_clock::now();

for (int i = 0; i < 5000000; i++)
{
    std::string Test = "AAAAAAAAAAAAAAA"; //15자
}

std::chrono::system_clock::time_point End = std::chrono::system_clock::now();

std::chrono::duration<float> Time = End - Start;
std::cout << Time << "\n";

 

1 ~ 15 글자에 대해 스트링을 생성할 때엔 평균적으로 2.7초가 소요되었다. (당연히 소요 시간은 환경에 따라 다를 수 있다.)

std::chrono::system_clock::time_point Start = std::chrono::system_clock::now();

for (int i = 0; i < 5000000; i++)
{
	std::string Test = "AAAAAAAAAAAAAAAA"; //16자
}

std::chrono::system_clock::time_point End = std::chrono::system_clock::now();

std::chrono::duration<float> Time = End - Start;
std::cout << Time << "\n";

 

반면, A를 딱 하나만 더 붙혀서 16자로 만들어서 string을 생성해보니 평균 4.8초가 소요되었다.

퍼센트로 보면 80%의 시간이 더 걸리는 셈이다.

 

급격하게 속도가 느려지는 것을 보니 16자 이상부터는 동적할당을 이용해 문자열을 관리하는 것 같다.

 

하지만, 이렇게 문자열을 담는 스택배열을 생성하게 되면 아무래도 메모리적으로는 효율적이지 못할 수 있을 것 같다는 생각이 들지만, 내부에선 union을 사용하여 동일한 메모리 영역을 문자열 길이에 따라 다르게 사용함으로써 효율적으로 관리하고 있다고 한다.