반응형
메모리 관리의 중요성
효율적인 메모리 관리는 프로그램의 성능을 향상시키고 메모리 누수를 방지하여 안정성을 높이는 데 중요한 역할을 합니다. C++에서는 메모리 관리 기법을 통해 성능 최적화를 도모할 수 있습니다.
메모리 관리 최적화 기법
1. 스마트 포인터 사용
스마트 포인터는 메모리 관리를 자동화하여 메모리 누수를 방지합니다. C++ 표준 라이브러리는 다양한 스마트 포인터를 제공합니다.
- std::unique_ptr: 독점적인 소유권을 가진 스마트 포인터입니다.
- std::shared_ptr: 공유 소유권을 가진 스마트 포인터입니다.
- std::weak_ptr:
std::shared_ptr
의 순환 참조를 방지하는 약한 참조 스마트 포인터입니다.
예제 코드
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() {
std::cout << "MyClass Constructor" << std::endl;
}
~MyClass() {
std::cout << "MyClass Destructor" << std::endl;
}
};
int main() {
{
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
// std::unique_ptr는 소유권을 가집니다.
} // 여기서 MyClass의 소멸자가 호출됩니다.
{
std::shared_ptr<MyClass> ptr2 = std::make_shared<MyClass>();
std::shared_ptr<MyClass> ptr3 = ptr2;
// std::shared_ptr는 참조 카운트를 증가시킵니다.
} // 마지막 std::shared_ptr가 범위를 벗어나면 MyClass의 소멸자가 호출됩니다.
return 0;
}
2. 메모리 풀 사용
메모리 풀은 미리 할당된 메모리 블록을 재사용하여 메모리 할당 및 해제의 오버헤드를 줄이는 기법입니다.
예제 코드
#include <iostream>
#include <vector>
class MemoryPool {
public:
MemoryPool(size_t size) : pool(size) {
for (size_t i = 0; i < size; ++i) {
freeList.push_back(&pool[i]);
}
}
void* allocate() {
if (freeList.empty()) {
throw std::bad_alloc();
}
void* ptr = freeList.back();
freeList.pop_back();
return ptr;
}
void deallocate(void* ptr) {
freeList.push_back(ptr);
}
private:
std::vector<char> pool;
std::vector<void*> freeList;
};
int main() {
MemoryPool pool(1024);
void* ptr1 = pool.allocate();
void* ptr2 = pool.allocate();
pool.deallocate(ptr1);
pool.deallocate(ptr2);
return 0;
}
3. 객체 재사용
빈번하게 생성되고 소멸되는 객체는 재사용을 통해 메모리 할당 및 해제의 오버헤드를 줄일 수 있습니다. 객체 풀(Object Pool) 패턴을 사용하여 구현할 수 있습니다.
예제 코드
#include <iostream>
#include <vector>
class MyObject {
public:
void reset() {
// 객체를 초기 상태로 재설정하는 코드
}
};
class ObjectPool {
public:
MyObject* acquire() {
if (pool.empty()) {
return new MyObject();
} else {
MyObject* obj = pool.back();
pool.pop_back();
return obj;
}
}
void release(MyObject* obj) {
obj->reset();
pool.push_back(obj);
}
private:
std::vector<MyObject*> pool;
};
int main() {
ObjectPool pool;
MyObject* obj1 = pool.acquire();
MyObject* obj2 = pool.acquire();
pool.release(obj1);
pool.release(obj2);
return 0;
}
실습 문제
문제 1: 메모리 관리 최적화
다음 코드에서 메모리 누수를 방지하고 효율적인 메모리 관리를 위해 스마트 포인터를 사용해보세요.
main.cpp
#include <iostream>
class MyClass {
public:
MyClass() {
std::cout << "MyClass Constructor" << std::endl;
}
~MyClass() {
std::cout << "MyClass Destructor" << std::endl;
}
};
int main() {
MyClass* ptr1 = new MyClass();
MyClass* ptr2 = new MyClass();
// 메모리 해제 누락
// delete ptr1;
// delete ptr2;
return 0;
}
해답:
main.cpp (최적화)
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() {
std::cout << "MyClass Constructor" << std::endl;
}
~MyClass() {
std::cout << "MyClass Destructor" << std::endl;
}
};
int main() {
{
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
std::unique_ptr<MyClass> ptr2 = std::make_unique<MyClass>();
// 스마트 포인터가 범위를 벗어나면 자동으로 메모리가 해제됩니다.
} // 여기서 MyClass의 소멸자가 호출됩니다.
return 0;
}
이제 다섯 번째 날의 학습을 마쳤습니다. 메모리 관리 최적화의 중요성과 다양한 최적화 기법을 이해하고, 실습 문제를 통해 이해를 높였습니다.
질문이나 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "불필요한 복사 방지 (copy elision)"에 대해 학습하겠습니다.
반응형
'-----ETC----- > C++ 성능 최적화 및 고급 테크닉 시리즈' 카테고리의 다른 글
[C++ 성능 최적화 및 고급 테크닉] Day 7: 데이터 로컬리티와 캐시 친화적 코딩 (0) | 2024.08.01 |
---|---|
[C++ 성능 최적화 및 고급 테크닉] Day 8: Move semantics와 R-값 참조 (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] Day 6: 불필요한 복사 방지 (copy elision) (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] Day 3: 코드 프로파일링 및 벤치마킹 (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] Day 4: 캐시 최적화 기법 (0) | 2024.08.01 |