메모리 구조: Heap과 Stack, 구조체와 클래스의 차이점

ggm-_-·2024년 10월 16일
0

TIL (Tody I Learn)

목록 보기
18/27

Unity의 C#을 사용한다고 가정하고 작성하였습니다. C나 C++같은 언어는 GC가 없다고 합니다.

메모리


메모리 영역

메모리는 Code, Data, Heap, Stack 4가지 영역으로 구분된다.

Code

프로그래머가 작성한 코드를 보관

Data

어플리케이션 전반에 필요한 데이터 저장
static const
프로그램 시작시 생성, 프로그램 종료시 삭제

Heap

객체(참조 데이터) 저장
new를 통해 생성, GC로 인해 삭제
In유니티) Instantiate(), Destroy()-> 참조만 끊고 결국엔 GC로 인해 삭제

Stack

로컬 변수, 매개변수 등, 어플리케이션에 필요한 데이터를 보관
에플리케이션 실행순서에 필요한 데이터 보관
데이터를 변수 할당시 생성, {} 끝날 때 삭제


Heap과 Stack의 메모리 동작

Stack의 메모리 동작

실행 1.

  • int x = 10;
    처음에 Stack 메모리 주소 맨 아래에 저장된다.

실행 2.

  • int y = x;
    x에 있는 값을 y로 가져온다.
    Stack 메모리의 x의 위에 y가 x의 값을 복사해와서 저장한다.

실행 3.

  • int x = 5;

  • 결과

x = 5, y = 10

x와 y는 연결되어 있지 않음!

Heap의 메모리 동작

Class는 참조형이다.
값형과 참조형의 차이는 Stack에 값이 직접 저장되냐, Stack엔 주소가 저장되고 값은 Heap영역에 저장되느냐의 차이다.

실행 1.

void Update()
{
	Monster orc = new Monster();
	Debug.Log(orc.Score);
}

Stack의 메모리 주소 맨 아래에 orc의 주소가 저장된다.
Heap영역에 orc의 데이터가 생성된다.
Update 한 번이 끝나면, Stack에 저장된 orc는 없어진다.
하지만, Heap에 저장된 orc의 데이터는 계속 남는다.
Update가 반복되면, Heap영역에 orc가 계속 생긴다.

그렇다면 여기서 Heap영역에 저장된 데이터는 언제 없어질까?

활용되지 않는 데이터 = 쓰레기 = 가비지 라고 불린다.
Heap영역에 버려진 가비지들은 가비지 컬렉터(GC)에 의해 언젠가는 사라진다.
그러나, 언제 사라질 지는 모른다.
이게 가비지 컬렉터의 단점이자, Heap메모리 영역을 사용할 때 잘 설계해야 하는 이유이다.
(참고로 Instansitate는 new를 한 거와 같다.)


Heap영역의 GC문제에 대한 해결책?

Unity의 Scene에서 생성되는 Cube 이런 것들도 다 클래스이다.
MonoBehavior를 계승한 객체들이다.

이런 것들을 어떻게 해결할까?
답은 재활용!
오브젝트 풀을 활용해 객체들을 파괴하지 않고 비활성화 시켜서 나중에 다시 사용할 때 Instaciate를 하지 않고 비활성화한 객체를 다시 활성화 시켜서 활용한다.


Vector3와 string 파헤치기

Vector3

Vector3는 구조체다.
구조체는 Stack에 저장되기 때문에 만들고 삭제하면 데이터가 바로바로 파괴된다.
Stack 메모리가 더 빠르다.

String

문자열 연산은 불변객체다.

실행 1.

string name = "GAME" + "game";

Heap영역에 있는 string 데이터 "GAME"에 "game"을 더하려고 한다면 새로운 Heap영역에 "GAME"과 "game"길이만큼의 공간을 확보한 후 연산을 진행한다.
이게 반복되면 엄청난 길이의 메모리가 필요하다.
string과 같은 방식으로 동작하는 것을 '파편화' 라고 한다.

문자열 연산의 해결책은?

  1. string은 보간 문자열($"")을 사용하는 게 좋다. ( $"Name: {name}")
  2. StringBuilder를 사용해서 문자열을 합친다.

구조체와 클래스의 차이점은?

값 형식과 참조 형식이라는 차이점이 있다.
이 특성 때문에, 구조체는 Stack에 할당되고 클래스는 Heap에 할당된다.
클래스는 Heap에서 메모리가 가비지 컬렉터에 의해 관리되고,
구조체는 Stack에서 바로바로 메모리가 사라진다.

클래스가 기본적으로 구조체보다 기능적인 측면에서 좋은 점이 많다.
하지만, 구조체는 단기적으로 빠르게 순환될 때 성능적으로 유리하다.


Data영역에 저장되는 static

static은 Data영역에 저장된다.
프로그램 시작시 생성되기 때문에 언제든지 사용할 수 있다.
Scene이 넘어가도 데이터가 계속 유지되어 있다는 특성이 있다.

그러나, static으로 만들었다고 바로 사용할 수 있는 건 아니다.
데이터를 할당 하지 않으면 null이다. 사용은 할 수 있지만, 데이터는 초기화를 해줘야 된다.
static을 작성할 때, Heap과 Stack영역에 있는 데이터를 바로 넣을 순 없다.

profile
미숙한 초보 게임 개발자
post-custom-banner

0개의 댓글