.NET Native AOT는 기존의 JIT(Just-In-Time) 컴파일 방식과 비교했을 때 메모리 점유율(Working Set)을 획기적으로 낮추는 특징이 있습니다. 소스에 따르면 Native AOT 애플리케이션은 관리형 버전보다 훨씬 적은 메모리를 사용하며, 주요 지표와 원인은 다음과 같습니다.

1. 메모리 절감 수치 및 환경별 차이

  • 평균 절감률: 실무 환경의 테스트 결과, Native AOT는 JIT 방식 대비 메모리 사용량을 약 45%가량 낮추는 것으로 나타났습니다. 이는 평균적으로 약 40MB 정도의 메모리 사용량을 절감하는 수준입니다.
  • Linux 환경의 이점: 특히 Linux 환경에서 메모리 절감 효과가 매우 두드러집니다. 관리형(JIT) 버전이 AOT 버전보다 약 1.5~2배 더 많은 RAM을 사용하며, 예를 들어 간단한 API 앱(Stage1)의 경우 AOT 버전은 56MB를 사용하는 반면 JIT 버전은 126MB를 점유합니다.
  • Windows 환경: Windows에서도 메모리가 절감되지만, Linux에 비해서는 그 차이가 상대적으로 작게 나타나는 경향이 있습니다.

2. 메모리 사용량이 낮은 이유

  • JIT 엔진 배제: Native AOT는 실행 시점에 JIT 컴파일러 자체와 컴파일에 필요한 메타데이터를 메모리에 올릴 필요가 없기 때문에 메모리 오버헤드가 적습니다.
  • 트리밍(Trimming) 적용: 빌드 과정에서 사용되지 않는 코드를 제거하고 꼭 필요한 런타임 라이브러리만 포함하는 단일 바이너리를 생성하기 때문에 메모리 공간을 효율적으로 사용합니다.
  • 소스 생성기 활용: 리플렉션 대신 소스 생성기를 사용하면 런타임 오버헤드가 사라져 메모리 사용량을 줄이는 데 추가적인 도움이 됩니다.

3. 비즈니스적 가치

  • 인스턴스 밀도 향상: 메모리 점유율이 낮기 때문에 동일한 인프라 자원에서 더 많은 컨테이너 인스턴스를 배치할 수 있습니다.
  • 비용 절감: 낮은 메모리 사용량과 작은 바이너리 크기는 결과적으로 클라우드 운영 비용을 약 12%에서 최대 20%까지 절감하는 효과를 가져옵니다.

4. 주의사항 및 예외

  • 제네릭 사용 시 주의: 제네릭 매개변수에 구조체(struct) 타입을 많이 사용하는 경우, 모든 조합에 대한 코드를 미리 생성해야 하므로 결과물 파일의 크기와 메모리 구조가 복잡해질 수 있습니다.
  • ReadyToRun(R2R)과의 차이: 또 다른 사전 컴파일 방식인 R2R의 경우, 파일 크기가 커짐에 따라 오히려 프로세스의 작업 세트(Working Set)가 증가할 수 있다는 점에서 Native AOT와는 다른 양상을 보입니다.

요약하자면: Native AOT는 실행 시점에 필요한 '컴파일 도구(JIT)'를 아예 챙기지 않고, 꼭 필요한 '짐(코드)'만 최소한으로 줄여서 출발하는 것과 같습니다.

이는 마치 **모든 요리 기구와 재료를 싣고 다니며 즉석에서 요리하는 '푸드 트럭(JIT)'**과 **미리 완성된 도시락만 가볍게 들고 가는 '소풍 바구니(Native AOT)'**의 차이와 같습니다. 바구니는 트럭보다 훨씬 가볍고 공간을 적게 차지하므로, 같은 장소(서버 노드)에 더 많은 바구니를 놓을 수 있는 것과 같은 원리입니다.

Posted by gurupia
,