티스토리 뷰
C++ 환경에서 접할 수 있는 대표적인 메모리 오류
1. 메모리 누수(Memory Leak)
- 'new'로 할당한 메모리를 해제하지 않을 때 쓰이지 않는 메모리가 지속적으로 쌓이면서 시스템 메모리를 고갈시킴
- 시간이 지날수록 프로그램 속도가 느려지고 나중에는 강제 종료가 되기도 함
2. 댕글링 포인터(Dangling Pointer)
- 메모리를 해제할 때 이미 해제한 메모리에 접근하다 발생하는 접근 오류
- 프로그램이 강제 종료될 수도 있음
3. 메모리 단편화(Memory Fragmentation)
- 잦은 할당과 해제로 만들어진 메모리 파편들이 후에 새롭게 할당 하는 것을 방해하는 문제
- 극단적으로 파편화된 메모리는 새로운 메모리 공간을 찾는 데 CPU 소모량이 높아지거나 결국 할당에 실패함
스택 메모리를 좀 더 똑똑하게 사용하자
스택 메모리 구조 이해하기
스택 메모리 특성
- 메모리의 시작점과 끝점, 마지막 할당지점이 있음
- 메모리를 할당할 때는 마지막 할당 지점 이후로 순차적으로 할당함
- 메모리를 해제할 때는 마지막 할당한 지점부터 순차적으로 해제함
- 메모리는 높은 주소에서 낮은 주소로 할당됨
- 메모리의 시작점과 끝점 뒤에 가드 영역이 존재하므로 가드영역에 접근하면 프로그램이 강제 종료됨
- 가드 영역은 디버그 모드와 릴리즈 모드에 따라 크기가 다름
**메모리 가드의 존재를 알려주는 예시**
스택 메모리 크기도 한계가 있다
문제점
- 스택 메모리는 스레드마다 기본적으로 1 MB 씩 주어짐
- 만약 큰 지역변수를 선언하게 되면 스택 오버플로우 오류가 발생하게 됨
예시
스택 메모리를 현명하게 사용하기
1. 크기가 큰 데이터를 만들지 말 것
가급적 모든 것을 작게 만드는 습관을 가져야 한다. 보통 데이터의 사이즈가 커지는 이유는 문자열이나 배열 때문이다.
STL의 string과 vector는 내부에서 동적 메모리인 힙을 이용하므로 데이터의 크기를 줄일 수 있다.
2. 크기가 큰 데이터는 전역변수나 정적변수를 활용
- 지역변수로 생성했을 때 오버플로우가 발생하면 전역변수나 정적변수로 바꾸면 해당 문제는 해결된다.
- 싱글톤 패턴을 사용해서 크기가 큰 데이터를 관리할 수 있다.
class CBigMemory
{
private:
CBigMemory() {}
~CBigMemory() {}
public:
char szBigSizeArr[10 * 1000 * 1000];
static CBigMemory* GetInstance()
{
static CBigMemory instance;
return &instance;
}
};
inline CBigMemory* Doc()
{
return CBigMemory::GetInstance();
}
int main()
{
memset(Doc()->szBigSizeArr, 0, sizeof(Doc()->szBigSizeArr));
}
3. 재귀함수를 만들지 말 것
재귀함수의 문제점
- 코드를 해석하기 어렵다.
- 스택 메모리 낭비가 크다.
- 너무 큰 값을 요청한 경우 스택 메모리 고갈로 프로그램이 강제 종료될 수 있다.
4. 링 메모리의 활용
class CRingMemory
{
unsigned char* m_pMemory; // 링 메모리 포인터
int m_nMemorySize; // 멤버 메모리 변수 사이즈
int m_nLastAllocPos; // 마지막 할당 위치
public:
CRingMemory() :m_pMemory(nullptr), m_nMemorySize(0), m_nLastAllocPos(0) {}
~CRingMemory() {}
// 링 메모리 생성 함수
// 원하는 사이즈의 링메모리를 생성
// 만약 생성이 되지 않으면 false 반환
bool Create(int nMaxSize)
{
m_pMemory = new(std::nothrow) unsigned char[nMaxSize];
if (nullptr == m_pMemory) return false;
m_nMemorySize = 0;
m_nLastAllocPos = 0;
return true;
}
// 링 메모리 파괴 함수
void Destroy()
{
if (m_pMemory) delete[] m_pMemory;
m_pMemory = nullptr;
}
// 링 메모리 할당함수
// 할당할 사이즈를 인수로 받아와서 데이터 할당
unsigned char* Alloc(int nSize)
{
if (m_nMemorySize < (m_nLastAllocPos + nSize)) m_nLastAllocPos = 0;
unsigned char* pNewMemory = m_pMemory + m_nLastAllocPos;
return pNewMemory;
}
};
'C++' 카테고리의 다른 글
[C++] 변수 네이밍 작성도 실력이다 (0) | 2023.09.10 |
---|---|
[C++] 정적 라이브러리 생성하고 활용하기 (0) | 2023.09.10 |
[C++] 프로젝트 초기 셋업은 어떻게?? (0) | 2023.09.09 |
[C++] 엔디언 변환 클래스 (2,4,8 byte 전용) (0) | 2023.07.24 |
[C++] string 변환 함수 정리 (1) | 2023.07.19 |