메모리 구조

2024. 4. 21. 19:25·CS

1. 프로그램의 메모리 구조 개요

프로그램이 실행될 때 운영체제가 할당하는 메모리 공간은 일반적으로 다음과 같은 주요 논리적 영역들로 나눌 수 있습니다. (실제 운영체제나 아키텍처에 따라 구현 방식은 다를 수 있지만, 개념적인 구분은 중요합니다.)

  1. 코드(Code) 영역 (또는 텍스트 영역): 실행될 프로그램의 기계어 코드(컴파일된 명령어) 자체가 저장되는 공간입니다. 읽기 전용(Read-only)이며, 프로그램 실행 중에 변경되지 않습니다.
  2. 데이터(Data) 영역: 프로그램이 시작될 때 할당되어 프로그램이 종료될 때까지 유지되는 데이터를 저장합니다. 주로 전역 변수(Global Variables)와 정적 변수(Static Variables)가 여기에 해당합니다. 보통 초기화된 데이터(.data)와 초기화되지 않은 데이터(.bss) 영역으로 다시 나뉩니다.
  3. 힙(Heap) 영역: 프로그램 실행 중에 동적으로 메모리를 할당하고 해제하는 공간입니다. 크기가 가변적이며, 주로 참조 타입 객체들이 저장됩니다. 가비지 컬렉터에 의해 관리됩니다.
  4. 스택(Stack) 영역: 메서드(함수) 호출과 관련된 정보(매개변수, 지역 변수, 복귀 주소 등)를 저장하는 공간입니다. LIFO(Last-In, First-Out) 구조로 작동하며, 매우 빠르고 효율적으로 메모리를 사용하지만 크기에 제한이 있습니다.

2. 스택(Stack) 영역: 지역 변수와 메서드 호출

스택 영역은 이름처럼 데이터가 쌓이는(Push) LIFO(후입선출) 방식의 메모리 구조입니다.

  • 주요 용도:
    • 메서드 호출 관리: 프로그램에서 메서드가 호출될 때마다 해당 메서드를 위한 스택 프레임(Stack Frame) 이 스택의 맨 위에 생성(Push)됩니다. 이 프레임에는 메서드 호출에 필요한 정보, 즉 메서드에 전달된 매개변수(Arguments), 메서드 실행 완료 후 돌아갈 복귀 주소(Return Address), 그리고 메서드 내부에서 선언된 지역 변수(Local Variables) 등이 저장됩니다. 메서드 실행이 완료되면 해당 스택 프레임은 스택에서 제거(Pop)됩니다.
    • 값 타입 지역 변수 저장: 메서드 내에서 선언된 int, float, bool 또는 struct와 같은 값 타입(Value Type) 지역 변수는 일반적으로 해당 메서드의 스택 프레임 내에 직접 할당됩니다.
    • 참조 타입 지역 변수 저장: 메서드 내에서 선언된 클래스 인스턴스, 배열, 문자열 등 참조 타입(Reference Type) 지역 변수의 경우, 참조(Reference) 자체(즉, 힙에 있는 실제 객체의 메모리 주소) 는 스택 프레임에 저장되지만, 객체의 실제 데이터는 힙 영역에 저장됩니다.
  • 특징:
    • 매우 빠른 할당 및 해제: 스택 포인터(Stack Pointer)를 이동시키는 것만으로 메모리 할당/해제가 이루어지므로 속도가 매우 빠릅니다.
    • 자동 메모리 관리: 메서드 호출이 시작될 때 자동으로 메모리가 할당되고, 메서드가 종료되면 자동으로 해제됩니다. 개발자가 명시적으로 메모리를 해제할 필요가 없으며, 가비지 컬렉션의 대상도 아닙니다(스택 자체 메모리 기준).
    • 크기 제한: 스택 영역은 일반적으로 운영체제나 프로세스에 의해 크기가 제한됩니다. 재귀 호출이 너무 깊어지거나 매우 큰 값 타입을 스택에 할당하려 하면 스택 공간을 초과하여 StackOverflowException 예외가 발생할 수 있습니다.
    • 짧은 수명: 스택에 저장된 데이터(지역 변수 등)는 해당 스택 프레임이 유효한 동안, 즉 해당 메서드가 실행 중인 동안에만 존재합니다. 메서드가 반환되면 관련 데이터는 사라집니다.

3. 힙(Heap) 영역: 동적 할당과 참조 타입

힙 영역은 프로그램 실행 중에 필요한 만큼 메모리를 동적으로 할당하고 사용하는, 스택보다 덜 구조화된 넓은 메모리 공간입니다.

  • 주요 용도:
    • 동적 메모리 할糖 (Dynamic Memory Allocation): 컴파일 시점에는 크기나 필요한 시점을 정확히 알 수 없는 데이터, 또는 메서드 호출 범위를 넘어서 오랫동안 유지되어야 하는 데이터를 저장하기 위해 사용됩니다.
    • 참조 타입 객체 저장: C#에서 new 키워드를 사용하여 생성되는 모든 클래스(Class) 인스턴스, 배열(Array), 문자열(String) 객체 등은 관리되는 힙(Managed Heap) 에 할당됩니다.
  • 특징:
    • 유연한 크기와 수명: 힙 영역의 크기는 필요에 따라 동적으로 늘어날 수 있으며(시스템 메모리 한도 내에서), 힙에 할당된 객체는 명시적으로 파괴되거나(Unity의 Destroy) 가비지 컬렉터에 의해 수거될 때까지 프로그램 실행 시간 동안 유지될 수 있습니다. 즉, 객체의 수명은 스택 변수처럼 특정 스코프에 묶이지 않습니다.
    • 상대적으로 느린 할당/해제: 힙에서 요청된 크기의 빈 공간을 찾아 할당하는 과정은 스택보다 복잡하고 시간이 더 소요될 수 있습니다. 메모리 해제는 가비지 컬렉터(GC) 가 담당하며, GC 실행 자체에도 CPU 시간과 자원이 소모됩니다.
    • 메모리 단편화 발생 가능: 다양한 크기의 객체들이 할당되고 해제되는 과정이 반복되면 힙 영역에 빈 공간들이 조각나는 외부 단편화(External Fragmentation) 문제가 발생할 수 있습니다.
    • GC의 대상: 관리되는 힙에 할당된 객체들은 더 이상 프로그램의 어떤 부분에서도 참조되지 않으면(Unreachable) 가비지로 간주되어 GC에 의해 메모리가 회수됩니다.

4. 데이터(Data) 영역: 정적/전역 변수

데이터 영역은 프로그램이 시작될 때 할당되어 프로그램 실행 내내 유지되는 데이터를 저장하는 공간입니다.

  • 주요 용도:
    • 정적 변수 (Static Variables): 클래스 내부에 static 키워드로 선언된 변수입니다. 이 변수들은 특정 객체 인스턴스에 속하는 것이 아니라 클래스 자체에 속하며, 프로그램 실행 동안 단 하나의 복사본만 존재합니다.
    • 전역 변수 (Global Variables): (C#에서는 엄밀한 의미의 전역 변수는 없지만, 다른 언어와의 비교 또는 static 변수의 넓은 의미로 사용될 때 언급됨). 프로그램 어디서든 접근 가능한 변수를 의미합니다.
    • 문자열 리터럴: 코드 내에 직접 작성된 문자열 상수("Hello World") 등도 보통 이 영역(또는 코드 영역과 가까운 곳)에 저장됩니다.
  • 세부 구분: 데이터 영역은 종종 다음과 같이 나뉩니다.
    • 초기화된 데이터 영역 (.data): 코드에서 명시적인 초기값을 가지는 정적/전역 변수들이 저장됩니다. (예: static int maxScore = 100;)
    • 초기화되지 않은 데이터 영역 (.bss - Block Started by Symbol): 코드에서 명시적인 초기값이 없는 정적/전역 변수들이 저장됩니다. 이 영역의 변수들은 프로그램 시작 시 운영체제나 런타임에 의해 보통 0 또는 null로 초기화됩니다. (예: static float currentTemperature;)
  • 특징:
    • 긴 수명: 데이터 영역의 메모리는 프로그램 시작 시 할당되어 프로그램 종료 시 해제됩니다.
    • 정적/전역 접근성: (접근 제한자에 따라 다르지만) 프로그램 실행 중 언제든 접근 가능할 수 있습니다.
    • GC 대상 아님: 데이터 영역 자체는 일반적으로 GC의 대상이 아닙니다. 하지만 정적 변수가 힙에 있는 객체를 참조할 경우, 그 참조되는 힙 객체는 GC의 대상이 될 수 있습니다.

5. 코드(Code/Text) 영역

  • 역할: 컴파일된 프로그램의 기계어 명령어가 저장되는 공간입니다. CPU는 이 영역의 명령어들을 순차적으로 읽어 실행합니다.
  • 특징: 일반적으로 읽기 전용(Read-only) 으로 설정되어 프로그램 실행 중에 코드가 변경되는 것을 방지하며, 실행 가능(Executable) 속성을 가집니다. 크기는 컴파일 시점에 결정됩니다. 데이터 저장보다는 프로그램의 로직 실행 자체와 관련됩니다.

6. 스택(Stack) vs. 힙(Heap) 비교 요약

Unity C# 개발에서 성능과 메모리 관리를 이해하는 데 가장 중요한 스택과 힙의 차이점을 요약하면 다음과 같습니다.

특징 (Feature) 스택 (Stack) 힙 (Heap)
주요 저장 대상 지역 변수 (값 타입), 메서드 호출 정보, 참조 변수 자체 참조 타입 객체 (new), 배열, 문자열
할당/해제 방식 자동 (스코프 진입/탈출 시) 동적 (new / GC에 의한 해제)
속도 매우 빠름 상대적으로 느림 (할당 및 GC 비용)
크기 제한적 (StackOverflow 가능) 큼, 동적 확장 가능 (시스템 메모리 한도 내)
수명 (Lifetime) 짧음 (스코프 벗어나면 자동 소멸) 유연함 (참조가 없어질 때까지 또는 GC 전까지)
관리 주체 OS / CLR (런타임) CLR / 가비지 컬렉터(GC)
단편화 발생하지 않음 발생 가능 (외부 단편화)

7. Unity 개발에서의 의미 (Implications in Unity Development)

이러한 메모리 구조에 대한 이해는 Unity C# 개발에 다음과 같은 실질적인 의미를 가집니다.

  • 값 타입 vs. 참조 타입 선택: 작은 데이터 구조를 정의할 때 struct(값 타입)를 사용하면 힙 할당 및 GC 부담을 줄일 수 있습니다 (스택 할당 또는 객체 내 임베딩). 하지만 큰 구조체는 복사 비용이 클 수 있으므로 주의해야 합니다. 복잡한 상태와 행동을 가지거나 공유되어야 하는 객체는 class(참조 타입)를 사용합니다. 이 선택은 메모리 사용 패턴과 성능에 직접적인 영향을 줍니다.
  • 가비지 컬렉션(GC) 최적화: 힙 영역에 객체가 할당될 때마다 잠재적인 가비지가 생성됨을 의미합니다. 따라서 Update()와 같이 자주 호출되는 곳에서 불필요한 new 키워드 사용, 문자열 연산, 박싱 등을 피하는 것이 GC로 인한 성능 저하를 막는 핵심입니다. 힙 할당 패턴을 이해하는 것이 GC 최적화의 첫걸음입니다.
  • StackOverflow 방지: 재귀 함수를 사용하거나 매우 깊은 함수 호출 구조를 설계할 때는 스택 오버플로 가능성에 유의해야 합니다.
  • 정적 변수(Static Variables) 관리: 정적 변수는 데이터 영역에 저장되어 앱 실행 내내 유지되므로, 싱글턴(Singleton) 패턴 구현이나 전역 설정 값 저장 등에 유용합니다. 하지만 씬 전환 시 자동으로 초기화되지 않으므로 상태 관리에 주의가 필요하며, 과도한 사용은 코드의 의존성을 높일 수 있습니다.
  • 성능 분석: Unity 프로파일러를 사용하여 메모리 사용량(Heap, Reserved 등)과 GC 할당(GC Alloc)을 분석할 때, 어떤 코드가 힙 할당을 유발하는지, 어떤 데이터가 스택이나 데이터 영역에 있는지 이해하면 문제의 원인을 파악하고 최적화 방향을 잡는 데 도움이 됩니다.

결론

Unity C# 프로그램이 실행될 때 사용하는 메모리는 크게 코드, 데이터, 힙, 스택 영역으로 나눌 수 있습니다. 특히 스택은 빠르고 자동으로 관리되지만 크기가 제한적이며 지역 변수(값 타입)와 메서드 호출 정보를 저장하는 데 사용되고, 힙은 동적으로 할당되며 참조 타입 객체를 저장하지만 가비지 컬렉션과 단편화의 고려가 필요한 영역입니다. 데이터 영역은 프로그램 실행 내내 유지되는 정적 변수 등을 저장합니다. 이들 각 메모리 영역의 역할과 특징, 그리고 값 타입과 참조 타입이 어디에 어떻게 저장되는지를 이해하는 것은 변수의 생명주기, 가비지 컬렉션의 영향, 성능 최적화 전략을 파악하는 데 근본적인 기초 지식을 제공합니다. 효과적인 메모리 관리는 안정적이고 성능 좋은 Unity 애플리케이션을 개발하기 위한 핵심 요소이므로, 이러한 메모리 구조에 대한 명확한 이해는 모든 Unity C# 개발자에게 필수적입니다.


참고 자료

  • Unity 매뉴얼 - 관리되는 힙 이해
'CS' 카테고리의 다른 글
  • 박싱(Boxing)과 언박싱(Unboxing)이란?
  • 1의 보수와 2의 보수 개념과 계산
  • 캡슐화, 상속, 다형성, 추상화
  • SOLID 원칙
뇌장하드 주인장
뇌장하드 주인장
  • 뇌장하드 주인장
    뇌장하드
    뇌장하드 주인장
    • 분류 전체보기 (86)
      • C++ (9)
      • C# (15)
      • CS (9)
      • 유니티 (38)
      • 유니팁 (7)
      • 유니티 패턴 (8)
      • - (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
뇌장하드 주인장
메모리 구조
상단으로

티스토리툴바