[C++] 동적 할당: malloc, free, void*, double free, Use-After-Free
동적 할당 1 (malloc, free)
인프런 Rookiss님의 'Part1: C++ 프로그래밍 입문' 강의를 기반으로 정리한 필기입니다.
😎[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 강의 들으러 가기!
메모리 구조 복습
코드 영역 | 실행할 코드가 저장되는 영역 |
데이터 영역 | 전역(global)/정적(static) 변수 |
스택 영역 | 지역 변수/매개 변수 |
힙 영역 | 동적 할당 |
문제 상황
문제 상황
- MM)RPG 동접 1명~5만명, 몬스터 1마리~500만마리
- 몬스터 생성 이벤트 -> 5분 동안 몬스터가 10배 많이 나옴
스택 영역
- 함수가 끝나면 같이 정리되는 불안정한 메모리
- 잠시 함수에 매개변수 넘긴다거나 하는 용도로는 OK
메모리 영역
- 프로그램이 실행되는 도중에는 '무조건' 사용됨
희망사항)
- 필요할때만 사용하고, 필요없으면 반납할 수 있는!
- 그러면서도 (스택과는 다르게) 우리가 생성/소멸 시점을 관리할 수 있는!
- 그런 아름다운 메모리 없나? -> HEAP
- 동적할당과 연관된 함수/연산자 : malloc, free, new, delete, new[ ], delete[ ]
커널 영역 vs. 유저 영역
유저 영역 [메모장] [LOL] [곰플레이어]
---------------------------------------
커널(Kernel) 영역 ( Windows 등의 핵심 코드)
유저 영역) 운영체제에서 제공하는 API 호출
커널 영역) 메모리 할당해서 건내줌
유저 영역) ㄳㄳ 잘쓸께요~
[ ]
- C++에서는 기본적으로 CRT(C Run Time Library)의 [힙 관리자]를 통해 힙 영역 사용
- 단, 정말 원한다면 우리가 직접 API를 통해 HEAP을 생성하고 관리할 수도 있음 (MMORPG 서버 메모리 풀링)
malloc, free 와 void*
malloc | - 할당할 메모리 크기를 건내준다 - 메모리 할당 후 시작 주소를 가리키는 포인터를 반환해준다 (메모리 부족 NULL) |
free | - malloc (혹은 기타 calloc, realloc 등의 사촌)을 통해 할당된 영역을 해제 - 힙 관리자가 할당/미할당 영부를 구분해서 관리 |
void* 무엇일까?
- * 가 있으니까 포인터는 포인터 (주소를 담는 바구니) => OK
- 타고 가면 void 아무것도 없다? => NO
- 타고 가면 void 뭐가 있는지모르겠으니까 너가 적당히 변환해서 사용해라 => OK
void* pointer = malloc(1000);
Monster* m1 = (Monster*)pointer;
m1->_hp = 100;
m1->_x = 1;
m1->_y = 2;
free(pointer)
만약에 free 하지 않으면 메모리 누수 발생
위의 코드에서 free(pointer)가 없으면 메모리 누수가 발생한다.
pointer를 사용하고 반환을 하지 않기 때문에 메모리를 차지하고 있어 언젠가는 메모리가 가득차 프로그램이 뻣는다.
Double free
- free를 두 번 하는 경우 대부분 크래쉬가 나고 끝난다.
#include <iostream>
using namespace std;
class Monster{
public:
int _hp;
int _x;
int _y;
};
Monster monster[500 * 10000]; // 상한선 숫자로 만든다. 몬스터가 1마리이면 메모리 낭비이다
int main(){
void* pointer = malloc(sizeof(Monster));
Monster* m1 = (Monster*)pointer;
m1->_hp = 100;
m1->_x = 1;
m1->_y = 2;
free(pointer); // 만약에 free 하지 않으면 메모리 누수 발생
// Double Free
free(pointer); // 이건 대부분 그냥 크래시만 나고 끝난다
return 0;
}
크레쉬 나고 끝난다.
Use - After - Free
#include <iostream>
using namespace std;
class Monster{
public:
int _hp;
int _x;
int _y;
};
Monster monster[500 * 10000]; // 상한선 숫자로 만든다. 몬스터가 1마리이면 메모리 낭비이다
int main()
{
void* pointer = malloc(sizeof(Monster));
Monster* m1 = (Monster*)pointer;
m1->_hp = 100;
m1->_x = 1;
m1->_y = 2;
free(pointer);
pointer = nullptr;
m1 = nullptr;
// Use-After-Free
// - 프로그래머 입장 : OMG 망했다!
// - 해커 입장 : 심봤다!
m1->_hp = 100;
m1->_x = 1;
m1->_y = 2;
return 0;
}
전체 코드
#include <iostream>
using namespace std;
class Monster{
public:
int _hp;
int _x;
int _y;
};
Monster monster[500 * 10000]; // 상한선 숫자로 만든다. 몬스터가 1마리이면 메모리 낭비이다
int main()
{
// Monster monster[500 * 10000]; //스택오버플로우(Stack Overflow). 뻗는다
void* pointer = malloc(sizeof(Monster));
Monster* m1 = (Monster*)pointer;
m1->_hp = 100;
m1->_x = 1;
m1->_y = 2;
// Heap Overflow
// - 유효한 힙 범위를 초과해서 사용하는 문제
// 만약에 free 하지 않으면 메모리 누수 발생
free(pointer);
pointer = nullptr;
m1 = nullptr;
// Double Free
// - 이건 대부분 그냥 크래시만 나고 끝난다
// free(pointer);
// Use-After-Free
// - 프로그래머 입장 : OMG 망했다!
// - 해커 입장 : 심봤다!
m1->_hp = 100;
m1->_x = 1;
m1->_y = 2;
return 0;
}
'⭐ Programming > C++' 카테고리의 다른 글
[C++] 타입 변환 1: 값, 타입 변환 / 암시적, 명시적 변환 (0) | 2022.04.08 |
---|---|
[C++] 동적 할당: new, delete (0) | 2022.04.07 |
[C++] 객체지향 마무리 (0) | 2022.04.06 |
[C++] 오버로딩과 오버라이딩의 차이 (0) | 2022.04.06 |
[C++] 연산자의 오버로딩 (Operator Overloading), 오버로딩 vs 오버라이딩 (0) | 2022.04.05 |
댓글
이 글 공유하기
다른 글
-
[C++] 타입 변환 1: 값, 타입 변환 / 암시적, 명시적 변환
[C++] 타입 변환 1: 값, 타입 변환 / 암시적, 명시적 변환
2022.04.08 -
[C++] 동적 할당: new, delete
[C++] 동적 할당: new, delete
2022.04.07 -
[C++] 객체지향 마무리
[C++] 객체지향 마무리
2022.04.06 -
[C++] 오버로딩과 오버라이딩의 차이
[C++] 오버로딩과 오버라이딩의 차이
2022.04.06