메모리 관리에 대한 탐구 (1) :: 메피카타츠의 블로그 (tistory.com)
메모리 관리에 대한 탐구 (1)
CS 면접 관련 질문들을 공부하면서 스마트 포인터에 대해 찾아보게 되었다. 이와 관련해서 안에 쓰여져 있는 내용들 중 잘 모르는 것이나 궁금한 것들을 찾아 꼬리에 꼬리를 물다보니 꽤나 오랜
mepkatatsu.tistory.com
당연한 얘기일지 모르겠지만 가비지 컬렉터에 관한 내용들을 찾다보니 메모리와 관련된 내용으로 귀결되었다. 이전에 메모리 관리에 대한 탐구 (1)이라고 쓴 이후로 2를 안썼는데, '가비지 컬렉터에서 가비지란 무엇인가?' 라는 내용으로 스택 영역과 힙 영역을 중심으로 정리한 이 글이 2탄이 되겠다.
스택 영역/힙 영역
가비지 컬렉터 이야기를 하기 위해 스택 영역과 힙 영역의 차이를 설명할 필요가 있겠다. 스택 영역에 생성되는 변수는 함수가 호출될 때 생성되고, 함수 호출이 완료되면 사라진다. 즉, 따로 메모리를 관리해줄 필요가 없는 것이고, 가비지 컬렉터도 관여하지 않는다. 따라서 가비지 컬렉터는 힙 영역에 할당되는 변수들에 한하여 관여를 하는 셈이다.
변수를 스택 영역에 할당하는 경우는 정적 할당이라고 한다. 고정된 크기를 갖기 때문에 메모리를 관리하기 편하고, 연속된 메모리 공간을 사용하여 성능도 좋다. 변수를 힙 영역에 할당하는 경우는 동적 할당이라고 한다. 가변적인 크기를 갖기 때문에 메모리를 관리하기 어렵고, 연속적이지 않은 메모리 공간을 사용하게 될 수도 있어 동적 할당에 비해 성능이 떨어진다. 크기가 정해져있지 않기 때문에 스택 영역에 할당하기 어려울 것이다.
즉, 스택 영역을 활용할 수 있다면 스택 영역을 활용하는 것이 좋은 선택이다. 하지만 동적 할당을 사용해야하는 경우도 있다. 배열의 크기가 계속 확장될 가능성이 있다면, 동적 할당을 하는 것이 현명한 선택일 것이다. 1시간 플레이를 하면 배열의 공간을 100까지 사용한다고 했을 때, 처음부터 10000까지 할당하는 것은 쓸데없이 메모리 공간을 많이 차지하게 된다. 이렇게 메모리 낭비를 감수하면서 여유있게 공간을 할당해도 100시간 이상 연속으로 플레이를 해서 필요한 공간이 10000이상으로 늘어나게 되면 오류가 발생한다. 즉, 이런 경우에는 동적 할당을 하여 힙 영역을 사용하는 것이 현명한 선택이다.
기존의 C나 C++에서는 이렇게 할당받은 메모리를 프로그래머가 직접 할당해줘야 했지만, 최근은 C++은 스마트 포인터로, C#과 Java는 가비지 컬렉터라는 기능을 통해 메모리를 자동으로 관리해준다. Unity에서는 C#을 사용하기 때문에 가비지 컬렉터의 도움을 받아 접근할 수 없는 메모리를 자동으로 해제해주며, 아까 말했듯이 가비지 컬렉터는 힙 영역에 할당되는 변수들에 한하여 관여를 한다.
값 형식/참조 형식
값 형식 - C# 참조 | Microsoft Learn
값 형식 - C# 참조
값 형식과 참조 형식, 값 형식의 종류, C#의 기본 제공 값 형식
learn.microsoft.com
참조 형식 - C# 참조 | Microsoft Learn
참조 형식 - C# 참조
참조 형식(C# 참조) 아티클 04/07/2023 기여자 12명 피드백 이 문서의 내용 --> C# 형식은 참조 형식과 값 형식 두 가지가 있습니다. 참조 형식의 변수에는 데이터(개체)에 대한 참조가 저장되며, 값 형
learn.microsoft.com
C#에는 값 형식과 참조 형식이라는 2가지 형식이 존재하는데, 값 형식은 구조 형식(struct)이거나 열거 형식(enum) 중 하나이며, 스택 영역에 할당된다.
딱히 생각해 본 적은 없었지만, C#에서 int도 하나의 구조체이다.
값 형식의 변수에는 해당 데이터가 직접 포함되지만, 참조 형식의 변수에는 데이터에 대한 참조가 저장된다는 차이점이 있다. 또한 참조 형식은 힙 영역에 데이터가 저장되며, 스택 영역에 힙에 있는 데이터의 주소를 저장한다. 이것은 추측이지만 함수 호출이 종료될 때 스택 영역에 있는 메모리들이 해제되며, 이때 힙에 있는 데이터의 주소들이 사라진다. 즉 힙에 접근할 수 없는 메모리가 생기게 되는 것이고, 이것이 가비지이며 힙에 메모리가 부족해질 때마다 이런 가비지들을 수집하는 것이 가비지 컬렉터의 일이라고 할 수 있을 것 같다.
참조 형식을 선언하는 데 사용되는 키워드로는 class, interface, delegate, record가 있다.
string이나 GameObject도 class이기 때문에 참조 형식이고, 동적 할당을 받아 힙 영역을 차지하는 셈이다.
이전 글에서 언급했듯, Vector2, Vector3는 new 키워드로 할당하지만 struct이기 때문에 값 형식이고, 정적 할당을 받아 스택 영역을 차지한다. 즉 가비지를 만들어내지 않는 것이다.
힙에 할당된 메모리의 크기를 확인
또한, 이전 글에서 new string("test"); 를 1000회 반복하고 프로파일러로 GC Alloc을 확인한 바가 있다. GC Alloc은 실제 가비지의 크기가 아닌, 힙에 할당된 메모리의 크기를 의미하는 것이라고 한다. 그도 그럴 것이, 힙에 할당되는 메모리 중에 쓰레기가 되는 메모리가 있고, 쓰레기가 되지 않는 메모리가 있으니 이것을 매 순간 판단하기는 어려울 것이다. 하지만 가비지 컬렉터의 속도는 GC Alloc의 총 크기에 영향을 받기 때문에 GC Alloc이 적게 발생하도록 하는 것이 좋을 것이다.
=================================
처음에는 가비지 컬렉터에 대해서 알아보려고 했는데, 가비지에 관한 내용을 먼저 정리할 필요를 느껴 먼저 가비지란 무엇인가에 대한 내용을 정리해보았다. 이전에도 스택 영역과 힙 영역에 대해 알아보았지만 많이 모자랐던 것 같다. 이제야 스택 영역과 힙 영역에 대해 확실하게 이해했다고 할 수 있을 것 같다. 다음에는 가비지 컬렉터가 작동하는 방식 등의 내용을 찾아보고, 실제로 가비지를 줄이는 방법 혹은 GC Alloc을 줄이는 방법에 대해 정리해 볼 생각이다.
추가로, 이전에 면접을 본 기업에서 1주일 이내로 연락을 준다고 했는데 연락이 없었다. 내가 지원하기 이전에 이미 클라이언트 프로그래머 수가 많이 늘었다고 해서 안 뽑힐 가능성도 염두에 두긴 했는데, 막상 떨어졌다 생각하니 조금 아쉬운 것 같다. 다시 자소서를 쓰고 다른 곳에 지원도 했는데, 여기도 공고가 오래전부터 올라와있어서 어떻게 될지는 잘 모르겠다. 시기도 별로 안 좋은 것 같기도하고, 안 좋은 시기에도 충분히 취업할 수 있을만큼 뛰어나지 못한 것 같기도 하다. 병역의 해결을 위해 취업하겠다는 목표를 세우긴 했으나... 병특을 뽑는 업체가 많지 않아서 내 마음대로 되는 것도 아니다. 이번에도 떨어지면 이전에 생각했던 스토어 출시를 목표로 게임 하나를 개발해볼까 싶은 생각을 가지고 있다. 크게 성공할 수 있을지는 모르겠지만 적어도 실패는 하지 않을 것 같은 게임이다. 일단 결과를 지켜볼 예정이다.
'개발 > 공부' 카테고리의 다른 글
메모리 관리에 대한 탐구 (4) - 가비지 만들기와 리소스 (0) | 2023.07.05 |
---|---|
메모리 관리에 대한 탐구 (3) - 가비지 컬렉터(C#) (0) | 2023.05.15 |
Unity에서의 Vector(Normalize/normalized와 Garbage) (1) | 2023.05.08 |
모바일 게임과 PC 게임의 차이 (0) | 2023.05.04 |
Race Condition, 동기화, 임계 영역, 스핀락, 뮤텍스, 세마포어 (0) | 2023.05.02 |