Replicated

[Teck Interview] C++, 동기, 비동기, 블로킹, 논블로킹, 게임 최적화 본문

지식

[Teck Interview] C++, 동기, 비동기, 블로킹, 논블로킹, 게임 최적화

라구넹 2025. 5. 28. 15:00

포인터와 참조의 차이

항목  포인터 (Pointer)  참조 (Reference)
선언 방법 int* p = &a; int& r = a;
널(null) 가능 가능 (p = nullptr;) 불가능 (항상 유효한 참조여야 함)
초기화 여부 나중에 초기화 가능 선언 시 반드시 초기화 필요
재지정 가능 여부 다른 객체를 가리킬 수 있음 한 번 정해지면 다른 객체 참조 불가
간접 접근 *p, p-> 직접 변수처럼 사용 (r)
메모리 주소 연산 가능 (&p, p++) 제한적 (&r은 실제 객체 주소)

 

virtual과 override

항목 virtual  override
정의 위치 기본 클래스(Base class) 파생 클래스(Derived class)
목적 함수가 파생 클래스에서 오버라이드 가능하게 함 해당 함수가 기본 클래스의 가상 함수 재정의임을 명시
오류 방지 여부 X (컴파일러가 재정의인지 확인 못함) O (재정의가 아니면 컴파일 에러)
사용 여부 최소 한 번 필요 (기반 클래스에서) 권장 (실수 방지에 유리)

 

Unity에서 GC 최소화 방법

- Obejct Pooling

 

Unreal Engine에서 UObject와 AActor의 차이점

항목 UObject AActor
기본 클래스 모든 언리얼 클래스의 기본 클래스 AActor는 UObject를 기반으로 한 UObject의 하위 클래스
씬에 존재 여부 월드/씬에 존재하지 않음 월드(레벨)에 배치 가능
트랜스폼(위치, 회전, 스케일) 없음 있음 (RootComponent 기준)
Tick 지원 여부 직접적으로 없음 (별도 처리 필요) Tick() 함수로 매 프레임 처리 가능
컴포넌트 추가 불가 가능 (UActorComponent, SceneComponent 등)
생성 방식 NewObject<UYourObject>() GetWorld()->SpawnActor<AYourActor>()
가비지 컬렉션 지원 지원
예시 용도 데이터 구조, 비동기 작업, 관리용 객체 캐릭터, 아이템, 환경 오브젝트 등

 

동기 vs 비동기 처리의 차이와 사용 예시

항목 동기(Synchronous) 비동기(Asynchronous)
처리 방식 작업이 순차적으로 진행됨 작업이 병렬적으로, 또는 콜백/이벤트 기반으로 진행됨
다음 작업 시작 시점 이전 작업이 완전히 끝난 후에 가능 이전 작업의 완료를 기다리지 않고 바로 다음 작업 시작 가능
코드 흐름 간단하고 예측 가능 복잡한 흐름, 콜백/이벤트/프라미스 필요
효율성 간단한 작업에 적합 네트워크, I/O, 멀티태스킹에 적합

 

비동기 처리 예

- 리소스 로딩, 서버 요청/응답 등

 

동기/비동기 - 블로킹/논블로킹

동기 vs 비동기

- 작업의 흐름 제어 방식

- 동기는 호출한 함수가 끝날 때까지 기다림

- 비동기는 기다리지 않고 나중에 알려줌

 

블로킹 vs 논블로킹

- 리소스 상태에 따라 호출자가 멈추는지 여부

- 블로킹은 결과를 기다리는 동안 CPU를 점유하며 멈춤

- 논블로킹은 작업이 완료되지 않았어도 즉시 리턴 (기다릴 상황이 있었지만, 기다리지 않고 즉시 돌아옴)

 

동기 + 논블로킹

- 가능함. 그냥 당장 결과 안나오면 실패해도 리턴하라.. 

- 소켓을 이렇게 열기도 가능

 

비동기 + 블로킹

- 가능함

- 비동기는 작업을 별도 흐름으로 실행하는 거고 블로킹은 호출자가 결과를 기다리는 거임

- 작업은 딴 데서 하는데, 꼭 필요하니까 끝날 때까지 기다린다,

 

작업 흐름이랑 기다리는 거랑 좀 다른 관점임

 

예시

UAssetManager::GetStreamableManager().RequestAsyncLoad(WeaponAsset, FStreamableDelegate::CreateLambda([&]() {
    UE_LOG(LogTemp, Log, TEXT("무기 로드 완료"));
}));

비동기로 로드. 이건 비동기 논블로킹

 

UAssetManager::GetStreamableManager().RequestSyncLoad(WeaponAsset);

이거 내부적으로 비동기 로딩하는데 블로킹함. 사실상 비동기 + 블로킹

 

FPS를 유지하기 위한 최적화 방법은 어떤 것이 있나?

일단 프로파일링해서 병목 지점 찾기

 

렌더링 최적화 (GPU)

- LOD -> 멀리있는 모델은 폴리곤 줄임

- Occlusion Culling -> 안보이는 객체는 렌더 안 함

- Instancing -> 같은 메시에 대한 Draw Call 줄이기

- Static Lighting -> 고정 조명은 Lightmap으로 베이크

- Shadow Distance -> 그림자 렌더 범위 줄이기

- Post Process 줄이기 -> 고비용 효과 제한

 

틱 최적화 (CPU)

- 불필요한 틱 안쓰기

- 틱 간격 늘리기 (TickInterval)

- Condition Tick

- Actor 수 줄이기

- 로직 분리 (타이머, 이벤트로 분산)

 

메모리와 GC(가비지 컬렉션)

- UObject 수 줄이기

- Short-lived 객체 줄이기

- 오브젝트 풀링

- Manual GC 관리 (특정 상황에선 직접 가비지 컬렉션 호출)

 

애니메이션 최적화

- Animation LOD .. 가까운 캐릭터만 풀 애니메이션 처리

- Update Rate Optimization

- Pose Caching .. 중복 계산 줄이기

- Blend 줄이기 .. 복잡한 블렌드 스페이스/노드 제한

 

AI/네비게이션 최적화

- AI 틱 줄이기

- Path Finding 빈도 제한

- EQS 빈도 제한

 

레벨 스트리밍, 로딩 최적화

- 레벨 분할

- 비동기 로딩 (LoadAsync, StreamableManager)

- 필요 리소스만 로딩

 

UI 최적화

- 틱 없는 UI (필요한 거만 사용)

- Visibility 제어 -> 안보이는 UI는 SetVisibility(ESlateVisibility::Collapsed); => 안보이고 공간도 차지 안함

- Retainer 사용 

 

* Retainer

- 자식 위젯을 캐시에 그려서 성능을 향상시키는 위젯

- 자식 위젯들을 한 번 렌더링한 뒤 텍스처로 저장해두고 매 프레임마다 다시 그리지 않고 저장된 결과만 표시

-> 렌더링 비용 절감

- 매우 자주 변하는 UI는 텍스처 캐시 생성 비용 때문에 오히려 역효과