개요
C++ 틱 베이스의 게임 서버에서 std::vector나 std::map을 매 초마다 수만, 수십만 회 생성하고 있는데 N시간이 지나면 이 코드에서 메모리 파편화(추정)가 심해져서 heap 할당 시에 CPU 사용량은 낮아지고 모든 스레드가 직렬화되는 문제가 확인되었다.
위 문제를 해결하기 위해서 pooling, 할당자 관련 도구를 찾다가 간단하게 정리해 보려고 포스팅하였다.
도구 한 줄 정리
boost object pool : 매우 큰 오브젝트 하나하나를 직접 다루기 좋은 도구.
boost pool_allocator : boost object pool 기반으로 할당해 주는 기능.
boost fast_pool_allocator : boost object pool 기반으로 할당해 주는 기능. 단일 스레드 앱에서 최적화.
tbb scalable allocator : 멀티 쓰레드 환경에서 쓰기 좋은 할당자, heap 할당 / 해제에서 직렬화되지 않으며 lock-free 하게 작동, 스레드를 오가면서 오브젝트 주체가 변경되어도 문제없음.
boost object pool 사용법
#include <iostream>
#include <boost/pool/object_pool.hpp>
class Test {
public:
Test() { std::cout << "Test object created\n"; }
~Test() { std::cout << "Test object destroyed\n"; }
};
int main() {
boost::object_pool<Test> pool;
Test* obj = pool.construct();
pool.destroy(obj);
return 0;
}
할당자 계열(그 외)
#include <iostream>
#include <vector>
#include <boost/pool/pool_alloc.hpp>
#include <tbb/scalable_allocator.h>
int main() {
std::vector<int, boost::pool_allocator<int>> vec;
// std::vector<int, boost::fast_pool_allocator<int>> vec;
// std::vector<int, tbb::scalable_allocator<int>> vec;
// 1000개의 정수 할당
for (int i = 0; i < 1000; ++i) {
vec.push_back(i);
}
// 벡터의 값을 출력
for (const int& val : vec) {
std::cout << val << " ";
}
std::cout << std::endl;
return 0;
}
결론
이렇게 간단하게 한 줄 추가하는 것 만으로 메모리 파편화가 쉽게 해결되고 풀링을 지원할 수 있다니 최고다!
하지만 어쨌든 좋은 도구를 쓰더라도 저런 단순 컨테이너 따위로 파편화가 발생하는 것은 바람직하지 않으므로 코드 정리도 반드시 하는 게 좋을 것 같다.
우리 프로젝트에서도 문제 클래스의 코드 정리와 tbb를 같이 적용해 두니 문제가 더 이상 문제가 발생되지 않게 개선되었는데 제발 더 이상 문제가 없기를 바란다. 🙏🙏🙏
'Programming > C++ & Unreal' 카테고리의 다른 글
C++ 스마트 포인터 메모리는 shared_ptr가 없어져도 해제되지 않는다. (0) | 2025.03.30 |
---|---|
vprintf, vsprintf 등 가변 인자 함수를 활용한 로그 함수 개발 시에 포맷 warning 출력하기 (0) | 2024.04.05 |
StackWalk64가 context에 의하여 Access violation를 유발 (1) | 2023.10.23 |
C++ 가변인자(va_list)를 오버로딩 하지 말자. (1) | 2023.10.23 |
C++ parallel for_each (thread) exception (1) | 2023.10.23 |
개요
C++ 틱 베이스의 게임 서버에서 std::vector나 std::map을 매 초마다 수만, 수십만 회 생성하고 있는데 N시간이 지나면 이 코드에서 메모리 파편화(추정)가 심해져서 heap 할당 시에 CPU 사용량은 낮아지고 모든 스레드가 직렬화되는 문제가 확인되었다.
위 문제를 해결하기 위해서 pooling, 할당자 관련 도구를 찾다가 간단하게 정리해 보려고 포스팅하였다.
도구 한 줄 정리
boost object pool : 매우 큰 오브젝트 하나하나를 직접 다루기 좋은 도구.
boost pool_allocator : boost object pool 기반으로 할당해 주는 기능.
boost fast_pool_allocator : boost object pool 기반으로 할당해 주는 기능. 단일 스레드 앱에서 최적화.
tbb scalable allocator : 멀티 쓰레드 환경에서 쓰기 좋은 할당자, heap 할당 / 해제에서 직렬화되지 않으며 lock-free 하게 작동, 스레드를 오가면서 오브젝트 주체가 변경되어도 문제없음.
boost object pool 사용법
#include <iostream>
#include <boost/pool/object_pool.hpp>
class Test {
public:
Test() { std::cout << "Test object created\n"; }
~Test() { std::cout << "Test object destroyed\n"; }
};
int main() {
boost::object_pool<Test> pool;
Test* obj = pool.construct();
pool.destroy(obj);
return 0;
}
할당자 계열(그 외)
#include <iostream>
#include <vector>
#include <boost/pool/pool_alloc.hpp>
#include <tbb/scalable_allocator.h>
int main() {
std::vector<int, boost::pool_allocator<int>> vec;
// std::vector<int, boost::fast_pool_allocator<int>> vec;
// std::vector<int, tbb::scalable_allocator<int>> vec;
// 1000개의 정수 할당
for (int i = 0; i < 1000; ++i) {
vec.push_back(i);
}
// 벡터의 값을 출력
for (const int& val : vec) {
std::cout << val << " ";
}
std::cout << std::endl;
return 0;
}
결론
이렇게 간단하게 한 줄 추가하는 것 만으로 메모리 파편화가 쉽게 해결되고 풀링을 지원할 수 있다니 최고다!
하지만 어쨌든 좋은 도구를 쓰더라도 저런 단순 컨테이너 따위로 파편화가 발생하는 것은 바람직하지 않으므로 코드 정리도 반드시 하는 게 좋을 것 같다.
우리 프로젝트에서도 문제 클래스의 코드 정리와 tbb를 같이 적용해 두니 문제가 더 이상 문제가 발생되지 않게 개선되었는데 제발 더 이상 문제가 없기를 바란다. 🙏🙏🙏
'Programming > C++ & Unreal' 카테고리의 다른 글
C++ 스마트 포인터 메모리는 shared_ptr가 없어져도 해제되지 않는다. (0) | 2025.03.30 |
---|---|
vprintf, vsprintf 등 가변 인자 함수를 활용한 로그 함수 개발 시에 포맷 warning 출력하기 (0) | 2024.04.05 |
StackWalk64가 context에 의하여 Access violation를 유발 (1) | 2023.10.23 |
C++ 가변인자(va_list)를 오버로딩 하지 말자. (1) | 2023.10.23 |
C++ parallel for_each (thread) exception (1) | 2023.10.23 |