• Feed
  • Explore
  • Ranking
/
/
    EnTT 분석하기

    ECS 는 무엇인가

    C++ECSEnTT
    W
    WillBig
    2025.04.07
    ·
    12 min read

    4681

    ECS(Entity-Component-System)란 무엇인가?

    ECS는 Entity(엔티티), Component(컴포넌트), System(시스템)으로 구성된 아키텍처로, 게임 엔진 및 데이터 중심 애플리케이션 개발에서 널리 사용되는 설계 패턴입니다.


    1. Entity (엔티티)

    • 역할:

      • 고유한 ID로 식별되는 객체.

      • 엔티티 자체는 데이터를 포함하지 않으며, 단순히 컴포넌트를 조합하기 위한 컨테이너 역할을 합니다.

    • 예시:

      • 게임 캐릭터, 몬스터, 아이템과 같은 객체는 각각 엔티티로 표현됩니다.

    2. Component (컴포넌트)

    • 역할:

      • 엔티티의 데이터를 저장하는 구조체 또는 클래스.

      • 하나의 컴포넌트는 특정 데이터를 나타내며, 동작에 대한 코드는 포함하지 않습니다.

    • 예시:

      • 위치 데이터: struct Position { float x, y; }

      • 체력 데이터: struct Health { int current, max; }

    3. System (시스템)

    • 역할:

      • 컴포넌트를 조작하거나 처리하는 로직.

      • 특정 컴포넌트를 가진 엔티티를 반복적으로 처리하며, 데이터를 읽고 수정합니다.

    • 예시:

      • 물리 시스템: Position 컴포넌트를 업데이트.

      • 렌더링 시스템: 화면에 Position을 기준으로 엔티티를 그립니다.


    ECS의 장점

    1. 고성능 데이터 접근:

      • ECS는 데이터 중심 설계(Data-Oriented Design)를 기반으로 하며, 데이터가 메모리에서 연속적으로 저장되므로 CPU 캐시 효율성이 높습니다.

      • 예를 들어, Position 컴포넌트 배열은 연속적인 메모리 상에 저장되어 반복문 처리 시 매우 빠릅니다.

    2. 유연성:

      • 엔티티에 필요한 컴포넌트만 추가하여, 객체 지향 설계(OOP)의 복잡한 상속 구조를 피할 수 있습니다.

      • 새로운 기능을 추가할 때 기존 코드를 수정하지 않고 컴포넌트를 추가하면 됩니다.

    3. 유지보수성:

      • 로직(System)과 데이터(Component)가 분리되어, 코드가 읽기 쉽고 테스트하기 쉬워집니다.

    4. 확장성:

      • 엔티티 수와 컴포넌트 종류가 증가해도 쉽게 확장 가능합니다.

    ECS의 단점

    • 학습 곡선:

      • ECS는 객체 지향 프로그래밍(OOP)과 다른 접근 방식이므로 초보자에게 다소 어려울 수 있습니다.

    • 초기 설계 비용:

      • ECS는 데이터와 로직의 명확한 분리가 필요하므로, 초기 설계에 더 많은 시간이 걸릴 수 있습니다.


    기존 방식의 컴포넌트 시스템과의 차이

    1. 기존 방식 구조

    • 유니티, 언리얼과 같은 OOP 기반 엔진에서:

      • 각 게임 객체(GameObject 또는 Actor)는 고유한 상태와 메서드를 가진 클래스 객체로 표현됩니다.

      • 컴포넌트는 게임 객체의 속성과 동작을 포함하는 서브클래스입니다.

      • 객체는 상속과 다형성을 사용하여 설계됩니다.

    예시: 유니티 방식

    public class Player : MonoBehaviour {
        public float health;
        public float speed;
    
        void Move() {
            // 이동 로직
        }
    
        void TakeDamage(float damage) {
            health -= damage;
        }
    }
    

    성능상의 한계

    1-1. 메모리 비효율성

    • 객체 지향 설계는 객체의 메타데이터(가상 함수 테이블, 포인터 등)를 저장하기 위해 추가 메모리를 사용합니다.

    • 게임 객체마다 고유한 메서드와 상태를 저장하기 때문에, 데이터가 메모리 상에서 연속적이지 않게 배치됩니다.

      • 결과적으로, 캐시 미스(cache miss)가 발생하여 CPU 성능이 저하됩니다.

    1-2. 캐시 비효율성

    • CPU는 데이터를 메모리에서 읽어올 때 연속적인 데이터(chunk)를 선호합니다.

      • OOP 방식에서는 객체들이 메모리 상에서 산발적으로 배치되므로, 동일한 유형의 데이터를 반복적으로 처리할 때 캐시 활용도가 낮습니다.

    1-3. 다형성으로 인한 런타임 오버헤드

    • OOP 기반 엔진은 상속과 다형성을 통해 기능을 확장합니다.

      • 다형성 사용 시, 런타임에 가상 함수 호출을 통해 메서드를 실행해야 하므로 성능 오버헤드가 발생합니다.

    2. ECS의 성능 개선

    성능상의 장점

    2-1. 데이터 중심 설계로 인한 캐시 효율성

    • ECS는 동일한 유형의 데이터를 메모리 상에서 연속적으로 배치합니다.

      • 이를 통해 CPU는 데이터를 캐시에 효과적으로 로드하여, 반복적인 작업에서 캐시 미스(cache miss)를 줄임.

    예시:

    • 기존 방식:

      4693
      • 메모리 상에서 객체별로 데이터가 섞여 있음.

      기존 방식에 대한 구체적인 접근

      2-2. 로직과 데이터의 분리

      • 객체 단위의 메모리 그룹화:

        • 기존 OOP 방식에서는 보통 객체(플레이어, 몬스터, 아이템) 단위로 풀(pool)을 관리합니다.

        • 이러한 풀은 동일한 유형의 객체를 묶어두는 구조이므로, 컴포넌트들이 서로 인접하게 배치될 가능성이 낮습니다.

        • 각 객체의 컴포넌트는 동적 할당되기 때문에, 실제로는 객체 내부의 컴포넌트조차 메모리에서 분리될 수 있습니다.

        • 따라서 이를 엔진 단위에서 메모리 할당 방식을 재설계 하지 않는다면 실제 데이터는 위 풀의 메모리 예시보다 더 파편적으로 존재할 수 있습니다.

    • ECS 방식:

      4695
      • 컴포넌트별로 데이터를 정렬하여 한 번에 처리 가능.

        • ECS 방식의 구체적인 접근은 다른 글 참조

    • ECS는 로직(System)과 데이터를 완전히 분리합니다.

      • 시스템은 데이터(컴포넌트)를 독립적으로 처리하며, 다형성을 제거하여 런타임 오버헤드를 줄입니다.

    2-3. 병렬 처리

    • 데이터가 연속적으로 정렬되어 있으므로, 멀티스레드 환경에서 병렬 처리 최적화를 쉽게 적용할 수 있습니다.


    3. 성능 차이를 구체적으로 보여주는 예시

    메모리 접근 패턴 차이

    기존 방식:

    • 객체 데이터가 비연속적으로 배치되어, 반복문에서 다수의 캐시 미스가 발생.

    Player Pool : [Player1(Position), Player2(Position), ...]
    Monster Pool : [Monster1(Position), Monster2(Position), ...]
    Item Pool : [Item1(Position), Item2(Position), Item3(Position), ...]
    
    • 각각의 엔티티 데이터를 읽기 위해 다른 메모리 주소에 접근해야 함.

    ECS 방식:

    • 동일한 컴포넌트를 가진 데이터가 연속적으로 배치되어 캐시 효율 극대화.

    Position Component Pool : [Position1, Position2, Position3, ...]
    
    • CPU는 한 번의 메모리 접근으로 다수의 컴포넌트를 캐시에 로드 가능.


    병렬 처리 효율성

    기존 방식:

    • 객체별로 상태와 메서드가 포함되어 있어, 병렬화에 적합하지 않음.

    ECS 방식:

    • 동일한 유형의 데이터를 처리하므로, 병렬 처리가 자연스럽게 이루어짐.

    • 예시: 1000개의 포지션 데이터를 업데이트할 때, 스레드를 나누어 병렬적으로 처리 가능.


    4. 결론

    ECS가 기존 방식보다 성능이 뛰어난 이유는 다음과 같습니다:

    1. 데이터 중심 설계:

      • 데이터가 연속적으로 배치되어, 캐시 효율성이 극대화됩니다.

    2. 로직과 데이터 분리:

      • 다형성을 제거하여 런타임 오버헤드를 줄이고, 유지보수성과 확장성을 향상합니다.

    3. 병렬 처리와 최적화 용이성:

      • 연속된 데이터 덕분에 병렬 처리가 용이해집니다.

    결과적으로, ECS는 대규모 엔티티와 컴포넌트를 효율적으로 처리해야 하는 게임 엔진이나 데이터 중심 애플리케이션에서 기존 방식에 비해 훨씬 더 나은 성능을 제공합니다.







    - 컬렉션 아티클