개발/C·C++
-
[메모리 풀링] 중앙 풀 + 스레드 로컬 슬랩(下편)개발/C·C++ 2025. 7. 3. 17:47
[메모리 풀링] 중앙 풀 + 스레드 로컬 슬랩(上편)에서 이어집니다. 전역 메모리 풀링의 문제점메모리 요청이 들어올 때마다 풀링 시스템에서 할당받고 반환하는 것은 효율적이지 않다고 했다. 락 프리이든 락이든 메모리 블록을 할당하고 반환할 때마다 경합이 발생할 수 있고, 그 요청과 반환 때마다 특정 로직이 실행되는 것이기 때문이다. 또한 메모리 블록이 파편화돼서 관리되기 때문에 캐시 혜택을 보기 어려운 상황이 된다는 것이 단점으로 지적된다. 스레드가 매번 새로운 메모리 블록을 사용하는 상황에서는, 기존 캐시 라인이 계속 무효화되기 때문에 새 캐시를 올리는 사이클이 추가된다. 메모리 풀링을 굳이 사용하지 않아도 되는 환경에서는 무시해도 되는 오버헤드일 수 있지만, 메모리 풀링을 적용해야 하는 환경이라면 고려..
-
[메모리 풀링] 중앙 풀 + 스레드 로컬 슬랩(上편)개발/C·C++ 2025. 7. 2. 16:01
요새는 정리할 모든 내용들을 노션에 남겼고 블로그는 사용을 잘 안 하게 됐다. 내 공부가 목적이기도 하고 노션이 아무래도 문서를 구조화하기에 특화되어 사용하기 편한 것도 있었다. 여기에서는 고민했던 과정을 남겨본다. 메모리 풀링의 필요성현대적인 OS에서는 힙 관리자가 성능이 좋아서 필요할 때마다 new/delete를 해줘도 된다는 말이 있다. 하지만 힙 관리자는 여전히 use-after-free 문제에서 자유롭지 못하고, 메모리 풀링을 하는 것보다 빠를 수는 없을 것 같다. 메모리 풀링이 필요한 환경이 여전히 존재한다. 메모리 풀링을 직접 구현해보고 싶을 때 전반적인 흐름이나 컨셉이 중요하므로 설명은 컨셉과 흐름에 중점을 두겠다. 메모리 풀링의 기본 흐름프로젝트에 적용한 기존 메모리 풀링 구조는 전역 락..
-
std::array 멤버 초기화의 다양한 방법개발/C·C++ 2025. 6. 12. 11:42
ChatGPT에 array 초기화 방법을 물어본 건 아닌데 질문이 조금 모호했는지 초기화 방법을 알려주네. 기왕 획득한 정보이니 아카이빙 해두자.1. 컴파일 타임(aggregate) 초기화struct X { // 모든 원소를 명시적으로 나열 std::array a1{ 1, 2, 3, 4, 5 }; // 일부만 나열하면 나머지는 0으로 채워짐 std::array a2{ 10, 20 }; // → {10,20,0,0,0} // C++20: C 배열에서 변환 constexpr static int raw[] = { 7, 7, 7, 7, 7 }; std::array a3 = std::to_array(raw); // → {7,7,7,7,7}};장점: 완전한 constex..
-
람다의 참조 캡처는 종종 불안하다개발/C·C++ 2024. 11. 22. 21:02
앞서, 콜백 함수의 인자는 C++17의 apply와 tuple을 이용해 처리할 수 있지만 예제를 최대한 간소화하기 위해 콜백 함수의 인자는 하나로 설정했다. 같은 이유로 요청을 처리할 함수는 멤버 함수가 아니라 전역 함수를 사용했다. 커맨드 패턴을 활용해 요청을 Job 객체로 만들어 큐에 넣고 공통 api-보통 커맨드 패턴에서는 Execute()를 애용하므로- Excute()를 호출해 Job(이하 일감)을 처리한다.일감을 실행하기 위한 callback 함수를 요청 객체에서 가지고 있다가 Execute()를 할 때 callback() 함수를 호출하는 구조를 단순홰해서 볼 건데 callback은 람다로 구현할 것이다. 이 때 람다 본문에서 필요한 변수들은 참조 객체를 해도 될까? 값 복사는 비용이 들고 참조..
-
VirtualAlloc()의 메모리 할당에 대해개발/C·C++ 2024. 10. 12. 20:39
VirtualAlloc()이 과거에는(?) 메모리 할당이 64KB 단위로 이루어졌던 것 같다.과거의 데이터로 학습한 Perplexity의 대답도 그렇고윈도우 시스템 프로그래밍 관련한 강의(최근에 제작된 것)에서도 관련한 내용으로 학습했다. 개인적으로 정리를 하던 와중에 정말 VirtualAlloc()으로 메모리 요청을 했을 때정말 최소 할당 값이 64KB이 궁금했고 테스트를 해봤다.현대적인 윈도우는 메모리 풀링을 하지 않고 new / delete만 써도 메모리 최적화가 잘 된다는 실무자 전언을 들었다.메모리 풀링을 하는 몇 가지 이유는 작은 메모리 공간을 요청에 대한 오버헤드가 큰 것과 작은 메모리 공간에 대한 잦은 할당과 반복이 메모리 단편화를 만들 수 있기 때문이다. 이 이야기를 들어서일까 Virtu..
-
64비트 시스템에서 메모리 정렬 경계에 대해개발/C·C++ 2024. 10. 11. 14:52
64bit 프로세서의 64bit 모드에서 메모리 동적할당을 하면 주소 값이 16바이트 정렬이 기본 값인 것 같다.struct PureNode{ int a; int b; int c;};int main(){ constexpr int ALIGN = 16; for (int i = 0; i (new PureNode()); uintptr_t node2 = reinterpret_cast(new PureNode()); uintptr_t node3 = reinterpret_cast(new PureNode()); uintptr_t node4 = reinterpret_cast(new PureNode()); uintptr_t node5 = reinterpret_cast(new PureNode()); ASSERT_C..
-
포인터 붕괴와 붕괴가 아닌 것개발/C·C++ 2024. 9. 28. 23:18
int형 2차원 배열을 선언한다.int buf[100][100]; 다음 둘의 주소 값이 같을까?cout 정답. O.2차원 배열의 첫 번째 행의 시작 주소를 가리킨다.auto를 이용해서 타입 확인을 해보면 타입이 다르다. 주소값은 같은데 타입이 다르다?무슨 의미일까. buf[0]은 사실상 int[100]의 시작 주소이므로 int* 타입으로 붕괴된다.문제는(?) &buf[0]인데, 이 표현식은 행 전체를 &으로 묶는 효과가 생긴다.타입은 (int*)[100]이 된다. 100개의 정수 배열에 대한 포인터다.조금 풀어서 이야기 하보면, buf[0]이 1차원 배열의 시작 주소를 가리키는데 이 앞에 주소 연산을 붙이니 1차원 배열 단위의 주소 연산을 할 수 있게 된다는 거다.코드로 확인해보자.auto p1 = ..
-
덧셈 연산 어셈블리 코드 간단 분석개발/C·C++ 2024. 9. 7. 00:29
다음 코드를 어셈블리로 봐보자. for (int i = 0; i 00007FF6993C57AA mov rax,qword ptr [counter] 00007FF6993C57B1 mov eax,dword ptr [rax] 00007FF6993C57B3 inc eax 00007FF6993C57B5 mov rcx,qword ptr [counter] 00007FF6993C57BC mov dword ptr [rcx],eax 1. mov rax, qword ptr [counter]- counter 변수의 주소값을 rax 레지스터가 담는다- 주소이기 때문에 8바이트를 읽어야 하므로 qword ptr이 사용된다2. mov ea..