zero-allocation 4

C# static abstract interface로 게임 수치 타입을 박싱 없이 설계하는 법

게임 코드에서는 대미지, 회복량, 이동 속도처럼 계산 방식이 비슷한 수치가 계속 등장한다. 이를 모두 float로 표현하면 구현은 빠르지만, 회복량을 대미지 인수에 넘기는 실수도 컴파일을 통과한다.인터페이스로 공통 연산을 묶을 수도 있지만, 기존 인터페이스는 Zero 같은 정적 값이나 +, * 연산자를 계약으로 선언하기 어려웠다. C# 11의 static abstract interface member를 사용하면 값 타입의 의미를 유지하면서 범용 수치 연산을 만들 수 있다.1. 연산자를 인터페이스 계약에 포함하기먼저 게임 수치가 제공해야 할 연산을 정의한다.public interface IGameStat where TSelf : unmanaged, IGameStat{ static abstract..

C#·C++ 모던 2026.07.19

C# 함수 포인터(delegate*)로 게임 핫패스의 delegate 힙 할당 없애기

게임 코드에서 콜백을 다룰 때 우리는 습관적으로 Action이나 Func 같은 delegate를 꺼낸다. 이벤트 버스, 상태 머신, 명령 큐, 데미지 계산 파이프라인까지 거의 모든 곳에 delegate가 들어간다. 문제는 이게 매 프레임 수천 번 도는 뜨거운 경로(hot path)에 올라타는 순간이다.delegate는 생각보다 무겁다. 람다가 지역 변수를 캡처하면 힙에 객체가 하나 생기고, 멀티캐스트면 호출 목록(invocation list)을 따라가며 간접 호출이 일어난다. 한두 번이면 무시할 만하지만, 1만 개 유닛이 매 프레임 각자 콜백을 부르면 이야기가 달라진다. GC 압박이 쌓이고 프레임이 튄다.C# 9부터 들어온 함수 포인터(delegate*)는 이 문제를 정면으로 푼다. 객체도 캡처도 없이 ..

C#·C++ 모던 2026.06.28

C# 12 [InlineArray]로 Unity 핫패스에서 힙 없이 고정 크기 버퍼 구현하기

왜 고정 크기 버퍼가 필요한가?게임 로직을 짜다 보면 "최대 8개 스킬", "최대 4명 파티원", "최대 16개 투사체" 같이 상한이 명확한 소규모 컬렉션을 수시로 만나게 된다. 가장 손쉬운 선택은 List나 T[]지만, 둘 다 힙 객체를 만들어 GC 추적 대상이 된다. 캐릭터가 1000명이고 스킬이 8개라면 별것 아닌 float[]가 1000개의 소형 힙 오브젝트로 쌓인다.그렇다고 unsafe fixed float[8]로 가자니 unsafe 블록이 코드 전반에 퍼지고, Unity DOTS의 IComponentData처럼 unmanaged 제약이 강한 컨텍스트에서는 fixed 버퍼조차 쓸 수 없는 경우가 생긴다.C# 12에서 도입된 [InlineArray] 어트리뷰트는 이 딜레마를 깔끔하게 해결한다. 단..

C#·C++ 모던 2026.06.14

Span<T>와 stackalloc로 Unity 핫패스에서 GC를 없애는 법

게임에서 프레임이 튀는 가장 흔한 원인 중 하나는 GC(가비지 컬렉션) 스파이크다. 평소엔 멀쩡하다가 갑자기 한 프레임이 16ms를 넘기면서 화면이 미세하게 끊기는 그 현상. 프로파일러를 열어보면 GC.Collect가 범인인 경우가 정말 많다. 매 프레임 돌아가는 Update 루프 안에서 무심코 만든 임시 배열, 문자열 결합, LINQ 한 줄이 힙에 쓰레기를 쌓고 있는 것이다.문제는 이걸 "최적화 나중에 하자"고 미루기 쉽다는 점이다. 핫패스에서 발생하는 작은 할당들은 개별적으로는 무해해 보이지만, 60fps 기준으로 초당 60번씩 쌓이면 결국 컬렉션을 강제로 트리거한다. 그리고 Unity의 기본 Boehm GC는 stop-the-world 방식이라, 컬렉션이 도는 순간 메인 스레드가 멈춘다.이 글에서는..

C#·C++ 모던 2026.05.31