전체 코드

1. 메모리 영역 복습

프로그램이 실행되면 메모리는 다음과 같은 영역으로 나뉩니다:

  1. 코드 영역 (Code Segment)

    • 실행할 코드가 저장되는 영역입니다.
    • 프로그램 시작 시 메모리에 로드되어 프로그램이 종료될 때까지 유지됩니다.
  2. 데이터 영역 (Data Segment)

    • 전역 변수(Global Variables)와 정적 변수(Static Variables)가 저장되는 영역입니다.
    • 프로그램이 실행될 때 할당되어 종료될 때까지 유지됩니다.
  3. 스택 영역 (Stack Segment)

    • 지역 변수(Local Variables)와 함수의 매개변수(Parameter)가 저장됩니다.
    • 함수가 호출될 때 메모리가 할당되고, 함수가 종료되면 메모리가 자동으로 해제됩니다.
    • 메모리 크기가 작고, 너무 많이 사용하면 스택 오버플로우(Stack Overflow)가 발생할 수 있습니다.
  4. 힙 영역 (Heap Segment)

    • 동적 할당된 메모리가 저장됩니다.
    • 프로그래머가 직접 메모리 할당과 해제를 관리해야 합니다.
    • 프로그램 실행 중에 크기를 유동적으로 조절할 수 있습니다.

2. 동적 할당이 필요한 이유

기존에는 데이터 영역과 스택 영역을 사용하여 프로그램을 만들었습니다. 하지만, 대규모 데이터를 처리할 경우 다음과 같은 문제점이 발생할 수 있습니다:

  • 스택 영역의 한계:
    스택 메모리는 함수가 종료되면 해제되므로, 장기간 유지할 데이터를 저장하기 어렵습니다.
  • 메모리 낭비:
    데이터 영역은 프로그램이 실행되는 동안 계속 유지되므로, 불필요한 메모리 사용이 발생할 수 있습니다.
  • 대규모 데이터 처리의 어려움:
    예를 들어, MMORPG 게임에서 5만 명의 유저가 접속 중이고, 몬스터가 500만 마리 생성된다고 가정하면, 스택과 데이터 영역만으로는 감당할 수 없습니다.

따라서, 필요할 때만 할당하고 사용이 끝나면 반납할 수 있는 힙(Heap) 영역을 활용하는 것이 효율적입니다.


3. 동적 할당 함수와 연산자

C와 C++에서는 동적 할당을 위해 malloc/freenew/delete를 사용합니다.

구분할당 함수해제 함수특징
C 스타일malloc(size_t size)free(void* ptr)- void* 반환, 크기 명시 필요
- 생성자 호출 안 됨
C++ 스타일newdelete- 타입 지정 가능, void* 변환 불필요
- 생성자 자동 호출
C++ 스타일 (배열)new[]delete[]- 배열 동적 할당 지원

(1) malloc/free (C 스타일)

#include <iostream>
using namespace std;

class Monster {
public:
    int _hp;
    int _x;
    int _y;
};

int main() {
    // malloc을 이용한 동적 할당 (C 스타일)
    void* pointer = malloc(sizeof(Monster));  // Monster 크기만큼 메모리 할당
    Monster* m1 = (Monster*)pointer;          // void* → Monster* 변환
    m1->_hp = 100;
    m1->_x = 1;
    m1->_y = 2;

    cout << "Monster HP: " << m1->_hp << ", 위치: (" << m1->_x << ", " << m1->_y << ")" << endl;

    // 할당된 메모리 해제
    free(pointer);
    pointer = nullptr; // 포인터 초기화
    return 0;
}

특징

  • malloc(size_t size)를 사용하여 원하는 크기의 메모리를 할당합니다.
  • void* 포인터를 반환하므로, 적절한 타입으로 캐스팅해야 합니다.
  • 생성자가 호출되지 않으므로, 객체 초기화를 수동으로 해야 합니다.
  • free(void* ptr)를 사용하여 메모리를 해제해야 합니다.

(2) new/delete (C++ 스타일)

#include <iostream>
using namespace std;

class Monster {
public:
    Monster() { cout << "Monster 생성됨!" << endl; }
    ~Monster() { cout << "Monster 소멸됨!" << endl; }
    
    int _hp;
    int _x;
    int _y;
};

int main() {
    // new를 이용한 동적 할당 (C++ 스타일)
    Monster* m2 = new Monster;  // 생성자 자동 호출
    m2->_hp = 200;
    m2->_x = 2;
    m2->_y = 3;

    cout << "Monster HP: " << m2->_hp << ", 위치: (" << m2->_x << ", " << m2->_y << ")" << endl;

    // 할당된 메모리 해제
    delete m2;  // 소멸자 자동 호출
    return 0;
}

특징

  • new 연산자를 사용하면 생성자가 자동으로 호출됩니다.
  • delete를 사용하면 소멸자가 자동으로 호출됩니다.
  • void* 캐스팅이 필요 없고, 타입을 명확히 지정할 수 있습니다.

(3) new[] / delete[] (배열 동적 할당)

int main() {
    // Monster 5마리 동적 할당
    Monster* m3 = new Monster[5];  // 생성자 5번 호출됨

    // 첫 번째 몬스터 설정
    m3[0]._hp = 300;
    m3[0]._x = 3;
    m3[0]._y = 5;

    cout << "Monster[0] HP: " << m3[0]._hp << ", 위치: (" << m3[0]._x << ", " << m3[0]._y << ")" << endl;

    // 메모리 해제
    delete[] m3;  // 소멸자 5번 호출됨
    return 0;
}

특징

  • new[]배열 형태로 여러 개의 객체를 할당할 때 사용합니다.
  • delete[]를 사용하지 않으면 메모리 누수가 발생합니다.

4. 동적 할당 시 주의할 점

  1. 메모리 누수 (Memory Leak)

    • 할당된 메모리를 free 또는 delete로 해제하지 않으면, 메모리가 계속 쌓이면서 누수가 발생합니다.
  2. Heap Overflow

    • 할당된 크기를 초과해서 사용하는 경우 발생할 수 있습니다.
  3. Double Free

    • 동일한 메모리를 두 번 해제하면 프로그램이 크래시될 수 있습니다.
  4. Use-After-Free

    • 해제된 메모리를 다시 사용하면 비정상적인 동작이 발생할 수 있습니다.

profile
李家네_공부방

0개의 댓글