센로그
[C#] 공용 언어 런타임 (Common Language Runtime; CLR) 본문
◆ CLR이란?
개발 플랫폼과 운영체제 사이의 닷넷 런타임. (가상머신)
- .NET의 가상머신 (Virtual Machine)
- 우리가 작성한 소스코드(C#, C++ 등)을 OS 위에 있는 .NET에서 동작하게 해주는 것
- C#의 경우, 빌드 후 IL(Intermediate Language, 중간 언어)로 변환되어 CLR에서 실행되는 구조이다.

◆ CLR의 구성 (기능)
CLR은 어떤 역할을 할까?

- Base Class Library 지원
- Collections, I/O, XML, DataType definition 등
- Thread 지원
- 멀티스레드의 병렬 실행을 관리하기 위한 스레드 지원
- Type Checker
- CTS(Common Type System)와 CLS(Common Language Specification)를 사용하여 형식을 검사
- 언어들 간의 차이점을 극복하고 동일한 동작을 보장하기 위함
- Exception Manager
- .NET Language에 상관없이 예외를 처리해줌
- Debug Engine
- 런타임동안 디버그가 가능함.
- JIT Compiler (Just-In-Time)
- 마이크로소프트 중간 언어(MSIL)를 실제 실행되는 컴퓨터 환경에 따라 특정한 기계 코드로 변환하는 컴파일러
- Garbage Collector
- 자동 메모리 관리.
- 더이상 필요하지 않는 메모리 공간을 자동으로 해제하여 재할당이 가능하도록 함
- CLR Loader
- 다양한 모듈, 리소스, 어셈블리 등을 로드함.
- 실제로 필요한 경우에 로드하는 온디맨드 방식 사용
◆ CLR의 동작 과정
C#에서 CLR이 어떻게 동작하는지 알아보자.

코드를 작성하고 실행하기까지의 과정은 다음과 같다.
- (사용자가) C# 소스코드 작성
- (C# 컴파일러가) 소스코드로부터 IL로 된 실행 파일을 만들어줌 (닷넷에서는 MSIL 사)
- (CLR의 JIT 컴파일러가) 사용자가 실행시 IL을 읽어 하드웨어가 이해할 수 있는 NativeCode로 컴파일 후 실행
장점
- Cross Platform 지원
- 플랫폼에 최적화된 코드를 만들어낼 수 있음
단점
- 실행 시 이루어지는 컴파일 비용이 추가됨
◆ CLR 가비지컬렉터의 동작원리
CLR은 기본적으로 런타임으로서의 역할과, 메모리 관리의 역할을 한다.
C# 어플리케이션은 실행되면 CLR이 해당 어플리케이션을 위한 메모리 공간을 제공하며, 이는 CLR에 의해서 관리되기 때문에 이를 Managed Heap이라고 부른다.
- 어플리케이션은 실행되면서 자신의 Managed Heap의 첫 주소를 가리키는 포인터를 가진다.

이때 힙 메모리를 참조하는 필드는 '루트 목록'으로 관리되며, 동적으로 힙 메모리를 할당할 때마다 루트 목록과 힙이 연결된다.
- 루트 목록: 시스템에서 직접 참조하는 목록
- static 변수, 레지스터에서 참조되는 값들, stack에 있는 변수들 등

각 어플리케이션의 Managed Heap은 그 공간이 유한하기 때문에 메모리 영역을 관리해주어야 한다.
이 '관리'는 CLR의 GC(Garbage Collector)가 담당한다.
GC의 기본적인 동작 방식은 다음 두 가지로 구성되어 있다.
- 선형 메모리 할당
- 단순 포인터 증가 방식으로 필요한 만큼의 메모리를 할당한다. (NextObjPtr++)
- 사용하지 않는 메모리 제거
두 가지 방식을 기반으로, 메모리가 수집되는 과정을 순차적으로 살펴보자.

- 새로운 객체에 메모리를 할당해야 하는 경우, 메모리가 부족하지 않으면 새로운 객체를 현재까지 적재된 바로 다음 위치에 적재하고, NextObjPtr을 증가
- 만약 메모리가 부족하다고 판단되면 메모리 수집을 위해 모든 객체를 Garbage로 가정
- 순차적으로 객체를 순회하며, 참조되고 있는 객체에 대해서 그래프 작성 (Reference Graph)
- 순회중 Object D와 같이 다른 객체를 참조하고 있는 경우, 참조된 객체 역시 그래프에 추가
- Object D에 이어서 Object H도 추가
- 이런 방식으로 도달 가능한 모든 객체를 재귀적으로 순회함
- 순회중 Object D와 같이 다른 객체를 참조하고 있는 경우, 참조된 객체 역시 그래프에 추가
- 순회 중 그래프에 추가된 객체를 다시 만날 경우 순회 중단.
- 모든 객체를 한 번씩만 순회하여 최적화하고 무한루프 방지. (그림에서 점선으로 표시된 부분-무한루프 가능성)
- 순회가 끝나면 만들어진 그래프에 존재하지 않는 객체를 Managed Heap에서 해제함
- 필요하다면, 그래프가 아닌 데이터를 빈틈없이 재배열함 (Compaction; 압축)
- 해제되어 Empty가 된 영역을 채우도록 당긴다는 뜻
- 객체 참조에 대한 포인터를 수정
- NextObjPtr 업데이트
참고
'게임 > Unity, C#' 카테고리의 다른 글
[C#] Task 메서드 비교 (0) | 2023.07.13 |
---|---|
[C#] StringBuilder (0) | 2023.07.11 |
[C#] static - Class, Constructor, Field, Method (0) | 2023.07.10 |
[C#] Extension Method (확장 메서드) (0) | 2023.07.10 |
[Unity] Awake(), Start(), OnEnable() 차이 (0) | 2023.07.07 |