센로그

[C#] 공용 언어 런타임 (Common Language Runtime; CLR) 본문

게임/Unity, C#

[C#] 공용 언어 런타임 (Common Language Runtime; CLR)

seeyoun 2024. 4. 11. 16:32

◆ 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이 어떻게 동작하는지 알아보자.

 

코드를 작성하고 실행하기까지의 과정은 다음과 같다.

  1. (사용자가) C# 소스코드 작성
  2. (C# 컴파일러가) 소스코드로부터 IL로 된 실행 파일을 만들어줌 (닷넷에서는 MSIL 사)
  3. (CLR의 JIT 컴파일러가) 사용자가 실행시 IL을 읽어 하드웨어가 이해할 수 있는 NativeCode로 컴파일 후 실행

 

 

장점

  • Cross Platform 지원
    • 플랫폼에 최적화된 코드를 만들어낼 수 있음

단점

  • 실행 시 이루어지는 컴파일 비용이 추가됨

 


◆ CLR의 동작원리

CLR은 기본적으로 런타임으로서의 역할과, 메모리 관리의 역할을 한다.

 

C# 어플리케이션은 실행되면 CLR이 해당 어플리케이션을 위한 메모리 공간을 제공하며, 이는 CLR에 의해서 관리되기 때문에 이를 Managed Heap이라고 부른다. 

  • 어플리케이션은 실행되면서 자신의 Managed Heap의 첫 주소를 가리키는 포인터를 가진다.

 

이때 힙 메모리를 참조하는 필드는 '루트 목록'으로 관리되며, 동적으로 힙 메모리를 할당할 때마다 루트 목록과 힙이 연결된다. 

 

 

 

 

각 어플리케이션의 Managed Heap은 그 공간이 유한하기 때문에 메모리 영역을 관리해주어야 한다.

이 '관리'는 CLR의 GC(Garbage Collector)가 담당한다.

 

 

GC의 기본적인 동작 방식은 다음 두 가지로 구성되어 있다.

  • 선형 메모리 할당
    • 단순 포인터 증가 방식으로 필요한 만큼의 메모리를 할당한다. (NextObjPtr++)
  • 사용하지 않는 메모리 제거

 

두 가지 방식을 기반으로, 메모리가 수집되는 과정을 순차적으로 살펴보자.

 

  1. 새로운 객체에 메모리를 할당해야 하는 경우, 메모리가 부족하지 않으면 새로운 객체를 현재까지 적재된 바로 다음 위치에 적재하고, NextObjPtr을 증가
  2. 만약 메모리가 부족하다고 판단되면 메모리 수집을 위해 모든 객체를 Garbage로 가정
  3. 순차적으로 객체를 순회하며, 참조되고 있는 객체에 대해서 그래프 작성 (Reference Graph)
    • 순회중 Object D와 같이 다른 객체를 참조하고 있는 경우, 참조된 객체 역시 그래프에 추가
      • Object D에 이어서 Object H도 추가
    • 이런 방식으로 도달 가능한 모든 객체를 재귀적으로 순회함
  4. 순회 중 그래프에 추가된 객체를 다시 만날 경우 순회 중단.
    • 모든 객체를 한 번씩만 순회하여 최적화하고 무한루프 방지. (그림에서 점선으로 표시된 부분-무한루프 가능성)
  5. 순회가 끝나면 만들어진 그래프에 존재하지 않는 객체를 Managed Heap에서 해제함
  6. 그래프가 아닌 데이터를 빈틈없이 재배열함 (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
Comments