JINTBEAT Design Life

🖥️ - Memory 구조 개요 본문

🖥️ - C language

🖥️ - Memory 구조 개요

jintbeat_design 2025. 6. 15. 02:03
반응형

일반적인 프로세스 메모리 구조는 다음과 같이 구성된다.

 

Memory 구조 - Stack/Heap/Data/Code 영역으로 나뉜다.

 

Stack ➡️ 높은 주소
Heap
BSS
Data
Code(Text) ➡️ 낮은 주소

 

Code 영역 (Text Segment)
  • 실행할 기계어 명령(즉, 컴파일된 코드)이 저장되는 영역
  • 읽기 전용(read-only)
  • 공유 가능(동일 프로그램 실행 시 코드 영역은 공유됨)
  • 함수들이 이 영역에 위치한다.
int add(int a, int b) {
    return a + b;
}

 

➡️ add 함수의 기계어 코드가 code 영역에 들어간다.

 

Data 영역(Data Segment)

static/global variable들이 저장되는 영역이다. 이 영역은 다시 2부분으로 나뉜다.

 

  • Initialized Data Segment(Data Segment)
    • 초기값이 있는 전역/정적 변수들이 저장된다.
    • ex)
int g_val = 10;
static int count = 3;
  • Uninitialized Data Segment(BSS Segment)
    • 초기값이 없는 전역/정적 변수들이 저장된다.
    • 실행 시 0으로 자동 초기화된다.
    • ex)
int g_uninit;
static int total;

 

Stack 영역
  • 함수 호출 시 생성되는 지역 변수, 매개변수, 리턴 주소등이 저장되는 LIFO 구조
  • 함수가 호출될 때마다 스택 프레임 생성
  • 함수가 종료되면 해당 스택 프레임은 제거됨(pop)
  • 컴파일러에 의해 자동으로 관리된다.

ex)

void foo() {
    int local = 5;  // stack에 저장
}

 

Heap 영역
  • 동적 메모리 할당(malloc, new)시 사용되는 영역
  • 프로그램 실행 중 크기 조절 가능
  • 직접 free() 해줘야 함(자동 소멸되지 않음)
영역 저장 대상 생성 시점 소멸 시점 관리 주체
Code 실행 명령어, 함수 코드 컴파일 타임 프로그램 종료 시 운영체제
Data 초기화된 전역/정적 변수 프로그램 시작 시 프로그램 종료 시 운영체제
BSS 초기화되지 않은 전역/정적 변수 프로그램 시작 시 프로그램 종료 시 운영체제
Stack 지역 변수, 매개변수, 리턴 주소 함수 호출 시 함수 종료 시 컴파일러
Heap 동적 할당 변수 (malloc) 런타임 동적 할당 직접 free  프로그래머 직접

 

  • new는 어떤 함수인가?
    • new는 연산자이다. C++에서 객체 또는 변수의 동적 메모리 할당을 위해 사용된다.
    • 메모리 할당 및 생성자 호출(클래스인 경우) 역할을 한다.
int* p = new int;     // int 1개 공간을 heap에 동적 할당
*p = 10;

[기본 형 변수 할당]

int* arr = new int[5];   // int 5개짜리 배열을 heap에 할당

[변수 할당]

class MyClass {
public:
    MyClass() { cout << "생성자 호출\n"; }
};

MyClass* obj = new MyClass();  // heap에 객체 생성 + 생성자 호출

[클래스 객체 생성]

할당된 메모리는 꼭! delete 또는 delete[]로 해제해야한다.
delete p;          // 단일 변수 해제
delete[] arr;      // 배열 해제
delete obj;        // 클래스 객체 해제
C와 비교 : malloc() vs new
비교 항목 C(malloc) C++(new)
메모리 할당 malloc(sizeof(int)) new int
타입 안전성 ❌ 수동 캐스팅 필요 ✅ 타입 자동 적용
생성자 호출 ❌ 없음 ✅ 클래스 생성자 호출됨
메모리 해제 free(p) delete p
배열 해제 수동 delete[] 필요

 

  • new는 C++에서만 제공되는 동적 메모리 할당 연산자이다.
  • C에서는 malloc() / calloc() 등을 사용해야 한다.
  • C++에서 객체 지향 프로그래밍(OOP)를 할 때 필수적으로 사용된다.
new 연산자의 작동 원리에 대해서 조금만 더 공부해보자
int* p = new int(42);

 

위 한 줄은 다음 3가지 작업을 자동으로 해주게 된다.

 

1. operator new 호출 ➡️ 메모리 할당(실제로는 malloc()과 유사하다)

void* raw_mem = operator new(sizeof(int));
  • 내부적으로 malloc() 또는 커스텀 할당자를 호출한다.
  • 실패하면 std::bad_alloc 예외를 던진다(C의 NULL과는 다르다)

2. 생성자 호출(초기화)

int* p = static_cast<int*>(raw_mem);
*p = 42;
  • 기본형(int, float 등)일 경우는 직접 초기화하고
  • 클래스일 경우에는 생성자(constructor)가 호출된다.

3. 최종 포인터 반환

  • 최종적으로는 p는 힙 영역에 생성된 변수/객체의 주소를 가리킨다.
delete?
delete p;

1. 소멸자 호출(~ClassName() 호출 - 객체인 경우)

2. operator delete 호출 ➡️ 내부적으로 free()와 유사한 방식으로 메모리 반환

 

malloc() 과의 비교 핵심 정리

항목 new/delete malloc() / free()
언어 C++ 전용 C / C++ 모두 사용 가능
메모리 할당 방법 operator new() 호출 malloc() 호출
생성자/소멸자 호출 ✅ 자동 호출 ❌ 수동 초기화 필요
실패 시 동작 bad_alloc 예외 발생 NULL 반환
오버로딩 가능 (operator new) 불가능

 

실무에서 많이 보는 커스텀 operator new
void* operator new(size_t size) {
    std::cout << "메모리 " << size << "바이트 할당\n";
    return malloc(size);
}
  • 클래스마다 operator new/delete를 오버로딩하면
    • 메모리 추적
    • 디버깅
    • 최적화된 allocator 적용 등이 가능함.
정리 요약

 

  • new는 단순한 malloc이 아니다.
    • 메모리 할당 + 생성자 호출 = new
  • C++ 객체지향의 핵심 기능인 생성자 호출을 자동으로 처리한다.
  • 예외를 던지므로 안정성과 추적 기능 면에서도 우위에 있다.
  • 고급 C++에서는 커스텀 operator new/delete로 성능 개선도 가능!

 

반응형