동적 할당
- 필요한 만큼의 메모리를 할당 받아 사용하는 것.
- 런타임에 운영체제에게 특정 크기 만큼의 메모리 할당을 요청하여 할당 받음.
- 메모리 할당 후 사용이 끝나면 꼭 메모리를 반납을 해줘야 함.
- 메모리 반납을 해주지 않을 경우, 메모리 누수(Memory Leak)가 발생하여 메모리를 계속 사용하게됨.
- 동적 할당 받은 메모리는 Heap 메모리 영역 사용.
malloc(), free()
- C언어부터 사용된 동적 할당을 위한 함수.
- malloc() 함수는 운영 체제로부터 할당 받은 메모리 주소를 void 자료형으로 반환해줌.
- void 자료형 반환 = 메모리에 뭐가 저장될지 모르겠으니, 너가 알아서 형변환해서 사용해라.
- 할당 받을 메모리 크기를 직접 지정.
예제 코드
#include <iostream>
using namespace std;
class Monster
{
public:
Monster() { cout << "Monster()" << endl; };
~Monster() { cout << "~Monster()" << endl; };
public:
int _hp = 100;
};
int main()
{
Monster* m = (Monster*)malloc(sizeof(Monster));
free(m);
return 0;
}
결과
new, delete
- C++언어에서 동적 할당을 위해 추가된 연산자.
- void 자료형이 아닌, 객체의 자료형을 반환.
- 할당 받을 메모리 크기를 알아서 할당해줌.
예제 코드
#include <iostream>
using namespace std;
class Monster
{
public:
Monster() { cout << "Monster()" << endl; };
~Monster() { cout << "~Monster()" << endl; };
public:
int _hp = 100;
};
int main()
{
Monster* m = new Monster;
delete m;
cout << endl;
Monster* m2 = new Monster[5];
delete[5] m2;
return 0;
}
결과
malloc(), free() 와 new, delete 차이점
- malloc(), free()는 클래스의 생성자와 소멸자를 호출하지 않지만 new, delete는 호출한다.
- malloc(), free()는 할당 받을 메모리 크기를 직접 입력하지만 new, delete는 자동으로 할당.
- malloc(), free()는 메모리 주소를 void 자료형으로 반환하지만 new, delete는 객체의 자료형으로 반환.
- new, delete는 [] 기호를 사용하여, 배열처럼 여러 개의 메모리를 동적 할당 받을 수 있음.
메모리 반납시, 반납해야할 메모리 크기를 어떻게 아는걸까?
- c++언어에서는 기본적으로 CRT(C언어 런타임 라이브러리)의 Heap 관리자를 통해 Heap 영역을 사용.
- 동적 할당을 받을 때, Heap 관리자는 요청한 만큼의 메모리 크기만 받는 것이 아니라, 동적 할당의 정보를 저장하기 위한 공간인 헤더 영역까지 할당을 받음.
- 헤더 영역은 실제 동적 할당 메모리의 바로 앞에 붙어있으며, 할당 받은 메모리 크기 등의 정보들이 저장되어 있음.
- 메모리 반납시 헤더의 내용을 참고하여 해당 메모리 크기 만큼 메모리 반납 수행.
주의 사항
메모리 누수 (Memory Leak)
- 동적 할당 받은 메모리 사용 후, 반납을 하지 않았을 경우 발생.
- 더 이상 사용하지 않는 메모리이지만, 반납을 해주지 않아 해당 메모리 크기만큼 메모리가 계속 사용되며 낭비됨.
- 언젠가 Heap 메모리가 부족해지는 Heap Overflow 가 발생하여 프로그램이 멈출 수 있음.
예제코드
#include <iostream>
using namespace std;
class Monster
{
public:
Monster() { cout << "Monster()" << endl; };
~Monster() { cout << "~Monster()" << endl; };
public:
int _hp = 100;
};
int main()
{
while (true)
{
Monster* m1 = new Monster;
}
return 0;
}
결과
- 메모리 동적 할당 후 반납을 해주지 않아, 반복문이 수행될 때마다 메모리가 계속 증가.
Use-After-Free
- 반납을 완료한 동적 할당 메모리를 참조하여 사용할 경우 발생.
- 이미 반납된 메모리이므로, 다른 곳에서 할당 받아 사용할 가능성도 있으며, 이때 해당 메모리를 참조하여 값을 변경할 경우 메모리 오염(Memory corruption) 발생.
예제 코드
#include <iostream>
using namespace std;
class Monster
{
public:
Monster() { cout << "Monster()" << endl; };
~Monster() { cout << "~Monster()" << endl; };
public:
int _hp = 100;
};
int main()
{
Monster* m1 = new Monster;
delete m1;
cout << "메모리 오염 전 hp : " << m1->_hp << endl;
m1->_hp = 200;
cout << "메모리 오염 후 hp : " << m1->_hp << endl;
return 0;
}
결과
- 메모리 반납 후 해당 메모리의 값이 초기화(0xdddddddd)됨.
- 이미 반납한 메모리를 다시 참조하여 값(200)을 넣어서 메모리 오염 발생.