메모리 단편화
메모리 단편화란
C++및 기타 프로그래밍 언어에서 발생할 수 있는 문제입니다.
프로그램에서 사용하는 메모리가 작은 블록으로 분할되어 새로운 개체나 데이터 구조에 할당할 대규모 연속 메모리 영역을 찾기 어려울때 발생하는 문제입니다.
(쉽게 말해 new와 delete를 많이 발생하면 생기는 문제)
이 문제로 인해 사용 가능한 총 메모리가 충분하더라도 프로그램이 새 개체 또는 데이터 구조에 충분한 메모리를 할당할 수 없는 상황이 발생할 수 있습니다. 이는 사용 가능한 메모리가 작은 조각으로 조각나고 요청을 충족할 만큼 충분히 큰 단일 메모리 블록이 없기 때문입니다.
메모리 단편화 해결방법
메모리 풀링
메모리 단편화에 대한 한 가지 해결방법은 메모리 풀링이라는 메모리 관리 기술을 사용하는 것입니다.
메모리 풀링은 프로그램 실행 시작 시 고정된 양의 메모리를 미리 할당하고 이를 고정된 크기의 청크로 나누는 것입니다
개체 또는 데이터 구조를 할당해야 하는 경우 풀에서 미리 할당된 청크를 할당할 수 있습니다. 개체 또는 데이터 구조가 더 이상 필요하지 않으면 재사용을 위해 청크를 풀로 반환할 수 있습니다.
메모리 풀링은 메모리가 효율적으로 관리되고 재사용될 수 있는 고정 크기 청크에 할당되도록 하기 때문에 메모리 단편화를 줄이는 데 도움이 될 수 있습니다.
그리고 더 효율적인 메모리 사용과 더 적은 단편화로 이어질 수 있습니다.
또한 메모리 풀링은 기본 메모리 할당 함수에 대한 호출 수를 줄여 성능을 향상시킬 수도 있습니다.
메모리 풀링 장점
- 메모리 단편화 감소 : 메모리 풀링은 고정 크기의 메모리 블록을 할당 및 할당 해제하여 메모리 조각화를 줄입니다. 이렇게 하면 시간이 지남에 따라 누적되어 성능 문제를 일으킬 수 있는 작고 사용할 수 없는 메모리 조각의 가능성이 줄어듭니다.
- 성능 향상 : 메모리 할당 및 할당 해제는 비용이 많이 드는 작업이며 메모리 풀링을 사용하면 이러한 작업을 수행해야 하는 횟수를 줄일 수 있습니다. 미리 할당된 메모리 블록을 재사용함으로써 메모리 풀링은 메모리 집약적인 애플리케이션의 성능을 향상시킬 수 있습니다.
- 예측 가능한 메모리 사용량 : 메모리 풀링을 사용하면 애플리케이션에서 사용하는 메모리 양을 더 예측 가능합니다. 메모리가 고정 크기 블록에 할당되기 때문에 응용 프로그램은 메모리 요구 사항을 보다 정확하게 예측하고 예기치 않은 메모리 급증을 방지할 수 있습니다.
- 맞춤형 메모리 관리 : 메모리 풀링을 통해 애플리케이션의 특정 요구 사항에 맞출 수 있는 맞춤형 메모리 관리 전략이 가능합니다. 예를 들어, 다양한 유형의 데이터 구조 또는 객체에 대한 메모리 사용을 최적화하기 위해 다양한 블록 크기로 메모리 풀을 생성할 수 있습니다.
메모리 풀링 예제
#include <iostream>
#include <vector>
class MemoryPool
{
public:
MemoryPool(size_t blockSize, size_t numBlocks) :
m_blockSize(blockSize),
m_numBlocks(numBlocks)
{
m_data = new char[blockSize * numBlocks];
for (size_t i = 0; i < numBlocks; ++i)
{
m_freeList.push_back(m_data + i * blockSize);
}
}
~MemoryPool()
{
delete[] m_data;
}
void* allocate(size_t size)
{
if (size > m_blockSize)
{
return nullptr; // 할당량이 너무 큽니다.
}
if (m_freeList.empty())
{
return nullptr; // 메모리 부족입니다.
}
void* ptr = m_freeList.back();
m_freeList.pop_back();
return ptr;
}
void deallocate(void* ptr)
{
m_freeList.push_back(ptr);
}
private:
char* m_data;
size_t m_blockSize;
size_t m_numBlocks;
std::vector<void*> m_freeList;
};
int main()
{
const size_t blockSize = 64;
const size_t numBlocks = 100;
MemoryPool pool(blockSize, numBlocks);
// 메모리 풀에서 메모리 할당
void* ptr1 = pool.allocate(32);
void* ptr2 = pool.allocate(64);
void* ptr3 = pool.allocate(128); // nullptr 반환
if (ptr1 && ptr2)
{
std::cout << "메모리 풀에서 메모리 할당\n";
}
// 메모리 풀로 메모리 반환
pool.deallocate(ptr1);
pool.deallocate(ptr2);
// 메모리 풀에서 더 많은 메모리 할당
void* ptr4 = pool.allocate(32);
void* ptr5 = pool.allocate(64);
if (ptr4 && ptr5)
{
std::cout << "메모리 풀에서 재사용된 메모리\n";
}
return 0;
}
'이론' 카테고리의 다른 글
STL 컨테이너 (0) | 2023.04.21 |
---|---|
얕은 복사와 깊은 복사의 차이 (1) | 2023.04.18 |
오버로딩과 오버라이딩의 차이 (0) | 2023.04.18 |
램버트 조명 공식 (0) | 2022.08.09 |
렌더링 파이프라인 구조 (0) | 2022.08.09 |
댓글