게임 스케일이 방대해지고 화면에 표현해야 할 객체의 수가 기하급수적으로 늘어남에 따라, 기존의 객체 지향 프로그래밍(OOP) 방식은 한계에 봉착했습니다. 유니티의 전통적인 MonoBehaviour 시스템은 사용하기 직관적이고 편리하지만, 수만 개의 오브젝트가 매 프레임
1. DOTS(Data-Oriented Technology Stack)의 등장 배경과 패러다임의 전환
게임 스케일이 방대해지고 화면에 표현해야 할 객체의 수가 기하급수적으로 늘어남에 따라, 기존의 객체 지향 프로그래밍(OOP) 방식은 한계에 봉착했습니다. 유니티의 전통적인 MonoBehaviour 시스템은 사용하기 직관적이고 편리하지만, 수만 개의 오브젝트가 매 프레임마다 Update() 함수를 호출하게 되면 엄청난 오버헤드와 캐시 미스(Cache Miss)가 발생하여 CPU가 제 성능을 발휘하지 못합니다. 이러한 병목 현상을 타개하기 위해 유니티 테크놀로지스가 야심 차게 도입한 것이 바로 데이터 지향 기술 스택인 DOTS(Data-Oriented Technology Stack)입니다. DOTS는 데이터의 메모리 배치 방식을 근본적으로 재설계하여, CPU의 L1, L2 캐시 히트율을 극대화하는 데 초점을 맞추고 있습니다. 이는 단순히 코드를 빠르게 실행하는 것을 넘어, 하드웨어가 낼 수 있는 물리적인 한계치까지 성능을 끌어올리는 패러다임의 전환을 의미합니다. 10만 개, 100만 개의 유닛을 프레임 드랍 없이 부드럽게 렌더링하고 시뮬레이션하기 위해서는 기존의 클래스(Class) 기반 사고방식에서 벗어나 철저하게 데이터(Data) 중심으로 아키텍처를 구상해야만 합니다. DOTS는 C# Job System, Burst Compiler, 그리고 핵심인 ECS(Entity Component System)로 구성되며, 이 세 가지 기술이 유기적으로 결합할 때 비로소 진정한 위력을 발휘합니다.
2. ECS(Entity Component System)의 아키텍처와 메모리 정렬의 마법
ECS는 기존의 GameObject-Component 구조를 완전히 해체하고 세 가지 개념으로 재구성합니다. 첫째, Entity는 아무런 데이터나 로직을 갖지 않는 단순한 고유 식별자(ID)입니다. 둘째, Component는 로직이 전혀 없이 오직 데이터(구조체, Struct)만을 담는 컨테이너입니다. 예를 들어 위치 정보를 담는 Position, 속도를 담는 Velocity 등이 있습니다. 셋째, System은 데이터(Component)를 순회하며 실제 로직(계산 및 변경)을 수행하는 역할을 담당합니다. 이 구조의 진정한 마법은 'Archetype(아키타입)'과 'Chunk(청크)'라는 메모리 관리 방식에서 나타납니다. ECS는 동일한 컴포넌트 조합을 가진 엔티티들을 같은 아키타입으로 분류하고, 이들의 데이터를 메모리 상의 연속된 청크 배열에 빽빽하게 저장합니다. 이렇게 데이터가 인접해 있으면, 시스템이 데이터를 순회할 때 CPU는 메모리에서 필요한 데이터를 한 번에 대량으로 캐시에 적재할 수 있어 캐시 미스가 사실상 제로에 가까워집니다. 반면 기존 OOP 방식에서는 힙(Heap) 영역 여기저기에 흩어진 객체들을 포인터로 찾아가야 했기 때문에 CPU가 메모리를 기다리는 데 시간을 허비했습니다. 이러한 ECS의 선형적인 메모리 배치가 바로 10만 개의 유닛의 위치와 상태를 단 몇 밀리초(ms) 만에 연산할 수 있게 해주는 가장 결정적인 이유입니다.
3. Burst Compiler와 C# Job System: 멀티코어 프로세싱의 극한
ECS가 데이터의 정렬을 책임진다면, C# Job System과 Burst Compiler는 그 데이터를 연산하는 속도를 극한으로 끌어올립니다. 현대의 CPU는 대부분 4코어에서 16코어 이상의 멀티코어 아키텍처를 가지고 있지만, 기존의 유니티 메인 스레드 구조에서는 이 자원들을 활용하기가 매우 까다로웠습니다. C# Job System은 개발자가 스레드 경쟁(Race Condition)이나 데드락(Deadlock)에 대한 걱정 없이 안전하고 쉽게 멀티스레드 코드를 작성할 수 있도록 돕습니다. 연산 작업을 작은 'Job' 단위로 쪼개어 워커 스레드(Worker Thread)들에 분배함으로써 병렬 처리의 이점을 극대화합니다. 여기에 Burst Compiler가 더해지면 성능 향상의 폭은 경이로운 수준에 도달합니다. Burst는 수학 기반의 연산에 특화된 LLVM 기반의 고성능 AOT(Ahead-Of-Time) 컴파일러입니다. 우리가 작성한 C# 코드를 런타임에 가장 최적화된 네이티브 기계어(Assembly)로 변환해주며, 특히 SIMD(Single Instruction Multiple Data) 명령어를 자동으로 생성하여 한 번의 CPU 사이클에 여러 개의 데이터를 동시에 연산할 수 있게 합니다. 이 두 기술의 결합으로 인해 10만 유닛의 길찾기, 충돌 감지, 상태 업데이트 로직을 60fps 환경 속에서도 메인 스레드의 부하 없이 완벽하게 처리해낼 수 있습니다.
4. 대규모 렌더링의 핵심: BatchRendererGroup (BRG)와 GPU 인스턴싱
연산 속도를 아무리 끌어올렸다 하더라도, 화면에 10만 개의 유닛을 그리기 위해서는 렌더링 파이프라인의 엄청난 혁신이 필요합니다. 유니티는 DOTS 환경에서의 압도적인 렌더링을 위해 Hybrid Renderer와 최신 BRG(BatchRendererGroup) API를 도입했습니다. 기존 방식대로 10만 번의 드로우 콜(Draw Call)을 GPU에 보낸다면 어떤 최고급 그래픽 카드라도 즉시 병목을 일으킬 것입니다. GPU 인스턴싱(Instancing)은 단일 드로우 콜로 동일한 메쉬와 머티리얼을 가진 수많은 객체를 동시에 그리는 기술입니다. DOTS 렌더링 파이프라인은 ECS 메모리에 있는 트랜스폼(Transform) 데이터 배열을 직접 GPU의 버퍼로 쏘아주어 메인 스레드의 개입을 최소화합니다. 특히 BRG는 렌더링해야 할 인스턴스의 트랜스폼, 색상, 기타 머티리얼 속성들을 거대한 배열(Culling 뷰 포함) 단위로 구성하여 GPU가 가장 효율적으로 처리할 수 있는 형태로 전달합니다. 여기에 더해, 카메라 시야 밖에 있는 수만 개의 유닛들을 걸러내는 프러스텀 컬링(Frustum Culling) 작업 역시 C# Job System과 Burst를 활용해 백그라운드 멀티스레드에서 순식간에 처리됩니다. 그 결과, GPU는 실제로 보여야 하는 유닛들만 최소한의 통신 비용으로 그려낼 수 있어 10만 단위의 방대한 군중 시뮬레이션이나 대규모 RTS 게임이 모바일 기기에서도 가능하게끔 만들어줍니다.
5. 실무 적용 시의 딜레마와 최적화 프로파일링 전략
DOTS는 강력하지만, 도입 시 치러야 할 비용과 러닝 커브도 상당합니다. 모든 것을 ECS로 전환할 필요는 없으며, 기존 MonoBehaviour 중심의 UI, 오디오, 카메라 컨트롤과 DOTS 시뮬레이션을 분리하여 사용하는 하이브리드(Hybrid) 접근이 실무에서는 가장 권장됩니다. 예를 들어 게임의 코어 로직과 대규모 유닛 처리는 ECS의 SubScene으로 구성하고, 플레이어 입력이나 메뉴 등은 기존 방식으로 처리하는 것입니다. 최적화 과정에서 프로파일러(Profiler)의 활용은 절대적입니다. Unity Profiler 창을 열어 Main Thread가 아닌 Worker Thread들에 Job이 고르게 분배되어 있는지, Garbage Collection(GC) 할당이 발생하고 있지는 않은지(Burst 컴파일 코드 내에서는 레퍼런스 타입을 사용할 수 없으므로 GC가 0이어야 함) 면밀히 체크해야 합니다. 또한 Entity Debugger 창을 통해 불필요한 아키타입 분절이 일어나지 않았는지 감시하고, Chunk가 지나치게 비어있는 현상(Chunk Fragmentation)을 최소화하기 위해 컴포넌트 설계를 재검토해야 합니다. 결과적으로 10만 개 렌더링의 성공 여부는 화려한 코딩 기교보다는, 메모리의 흐름을 이해하고 병목 지점을 정확히 프로파일링하여 데이터의 정렬 상태를 치밀하게 관리하는 테크니컬 아티스트와 프로그래머의 협업 능력을 통해 결정됩니다.
결론 및 요약
유니티의 DOTS와 ECS 아키텍처는 게임 개발의 한계를 다시 쓰는 혁명적인 도구입니다. 데이터의 연속적인 메모리 배치, C# Job System을 통한 멀티스레딩, Burst Compiler의 기계어 최적화, 그리고 BRG 기반의 GPU 인스턴싱이 완벽하게 맞물릴 때 10만 개 이상의 유닛 렌더링이라는 경이로운 성과를 달성할 수 있습니다. 비록 초기 학습 곡선이 가파르고 기존의 객체 지향적 사고방식을 버려야 하는 고통이 따르지만, 이 기술을 마스터하는 순간 모바일과 PC를 가리지 않고 타협 없는 극한의 성능을 게임에 부여할 수 있게 됩니다. 대규모 전투, 수많은 NPC가 살아 숨 쉬는 도시, 복잡한 시뮬레이션 게임을 구상하고 있다면, DOTS는 더 이상 선택이 아닌 생존을 위한 필수 무기가 될 것입니다.