Stack Memory
- 처음 생성되는 변수가 메모리 공간의 가장 위쪽(높은 주소값)을 차지한다.
- 위에서 아래로 변수가 쌓인다.
- 포인터 변수
- 구조체, 클래스
- 아래 구조체의 경우 멤버변수의 크기만 합하면 8byte 이지만, 메모리 패딩이 발생해서 10 byte 를 차지한다.
- 아래 클래스에서 함수는 크기를 따로 차지하지 않는다.
- 포인터는 8byte 차지
struct ST
{
long a; //4 byte
int b; //4 byte
short c;//2 byte
};
class Cat
{
public:
void printCat();
private:
int age; //4byte
float weight;//4byte
};
int main()
{
std::cout << sizeof(long) << std::endl; //4 byte
std::cout << sizeof(ST) << std::endl; //12 byte
std::cout << sizeof(Cat) << std::endl; //8 byte
Cat cat1;
Cat* catptr = &cat1;
std::cout << sizeof(catptr) << std::endl; //8byte
return 0;
}
- Stack Frame
- 메모리 스택은 변수 단위로 쌓이는 것이 아니라 stack frame 단위로 function call에 따라 쌓이고 해제되는 것이 반복된다.
- 메모리 스택 분석(아래 코드의 동작 방식)
class Cat
{
public:
Cat()
{
m_age = 1;
}
~Cat();
void AddAge(int arg)
{
m_age += arg;
}
private:
int m_age;
};
int main()
{
Cat cat;
cat.AddAge(10);
return 0;
}
Heap Memory
- Stack Memory : 메모리가 쌓일 때는 올라가면서 쌓이고 없어질때는 위에서부터 없앤다. (top이 기준)
- Heap Memory : 그냥 쌓인다. 포인터가 메모리를 가리키는 방
- Heap Memory 의 사용 이유
- life cycle :
-> heap 메모리에 필요한 데이터를 넣어준다. (by pointer)
-> stack 메모리가 끝나면서도 사라지지 않게 한다.
- large size :
-> 값을 저장할 때 큰 메모리를 차지하는 것을 heap 메모리에 넣어두고 stack 메모리에는 heap 메모리를 가리키는 포인터만 가지게 한다.
- dynamic(runtime) :
-> stack 메모리는 컴파일 시간에 결정
-> 포인터만 stack 메모리에 가지고 heap 메모리에서는 동적인 생성이 가능하다.
- Heap 메모리 사용시 메모리 leak 방지가 매우 중요하다.
- C style : free를 이용해서 해제할 때마다 써줘야 한다.
- C++ style : delete를 이용해서 해제할 때마다 써줘야 한다.
- C++ Smart Pointer OR Vector
- 사용이 끝나면 스스로 메모리 해제를 해준다.
- free와 delete 보다 smart pointer나 vector를 사용하자
//unique_ptr
std::unique_ptr<Widget> WidgetPtr = std::make_unique<Widget>();
//vector
std::vector<Widget> WidgetVec(10);
Heap, Stack, Static
- Stack :
-> 위에서부터 아래로 띄는 간격 없이 쌓임(stack frame단위)
-> allocate, disallocate가 빠르다.
-> dynamic allocate는 불가능
-> 큰 메모리 할당시 stack overflow 발생 가능
- Heap :
-> 비어있는 공간을 찾고(프로그램 실행 도중) 아래에서부터 위로 쌓인다.
-> allocate, disallocate가 느리다.(stack 보다)
-> dynamic allocate 가능
-> 큰 메모리 할당에 유리
- Static, Global :
-> heap 메모리 아래쪽에 존재