Unity 6000.5.3f1 통제 실험에서 나온 GC.Alloc 이벤트 수와 NonAlloc 버퍼 포화 결과를 옮긴 설명도입니다.
Unity 6000.5.3f1 통제 실험에서 나온 GC.Alloc 이벤트 수와 NonAlloc 버퍼 포화 결과를 옮긴 설명도입니다.

600회 호출에서 1200회, 20회, 0회

Unity 6000.5.3f1 빈 프로젝트에서 문자열 경로를 120회 예열한 뒤 600번씩 호출했습니다. 현재 스레드의 Internal/GC.AllocProfilerRecorder로 합산하니 매 호출마다 $"Score: {score}"를 만든 경로는 1200회, 점수가 60회 호출마다 바뀔 때만 만든 경로는 20회, 같은 값 42를 가드 앞에 둔 경로는 0회였습니다. 이 숫자는 ProfilerRecorderSample.Count로 센 GC.Alloc 이벤트 수입니다. Recorder의 UnitType은 TimeNanoseconds였으므로 원시 Value를 바이트처럼 쓰지 않았습니다.

using TMPro;
using UnityEngine;

public sealed class ScoreLabel : MonoBehaviour
{
    [SerializeField] private TMP_Text label;
    private int shownScore = int.MinValue;

    public void SetScore(int value)
    {
        if (value == shownScore)
            return;

        shownScore = value;
        label.text = $"Score: {value}";
    }
}

배열 반환은 200회, 재사용 버퍼는 0회

40개의 SphereCollider를 쿼리 반경 안에 두고 Physics.OverlapSpherePhysics.OverlapSphereNonAlloc을 각각 200번 호출했습니다. 배열을 반환하는 OverlapSphere에서는 200개의 GC.Alloc 이벤트가 잡혔고, 64칸 배열을 재사용한 NonAlloc 경로에서는 0개였습니다. 이 결과는 통제한 Editor 호출의 현재 스레드만 잰 값이며 실제 게임 한 프레임 전체의 할당량은 아닙니다.

using System;
using UnityEngine;

public sealed class NearbyTargets : MonoBehaviour
{
    private const int MaxHits = 256;
    [SerializeField] private float radius = 4f;
    [SerializeField] private LayerMask targetMask;
    private Collider[] hits = new Collider[32];

    public int QueryNearby()
    {
        while (true)
        {
            int count = Physics.OverlapSphereNonAlloc(
                transform.position, radius, hits, targetMask,
                QueryTriggerInteraction.Collide);

            if (count < hits.Length)
                return count;

            if (hits.Length >= MaxHits)
            {
                Debug.LogWarning($"Nearby target buffer reached {hits.Length}; result may be truncated.");
                return count;
            }

            Array.Resize(ref hits, Math.Min(hits.Length * 2, MaxHits));
        }
    }
}

반환값이 배열 길이와 같으면 포화로 취급합니다

활성 Collider가 정확히 8개일 때도 8칸 버퍼의 반환값은 8이었고, 활성 Collider가 40개일 때도 8이었습니다. count == hits.Length만 보고 정확히 다 담겼는지 잘렸는지 구분할 수 없습니다. 위 코드는 이 경우 배열을 늘려 다시 묻습니다. Array.Resize는 포화 순간에 할당하므로 시작 크기와 최대값은 실제 밀집도를 보고 정하고, 고정 상한에 닿으면 결과가 잘릴 수 있음을 남겨야 합니다.

실제 프로젝트에서는 대상 빌드에서 다시 잽니다

Development Build와 Autoconnect Profiler로 같은 장치, 씬, 입력을 반복하세요. CPU Usage의 GC Alloc 열에서 프레임을 고정하고 Allocation Call Stacks로 첫 할당 지점을 찾습니다. Deep Profile은 범위를 좁힌 뒤 잠깐만 켭니다. 목표는 숫자를 억지로 0으로 만드는 게 아니라 반복 호출에서 생기는 불필요한 할당을 없애는 것입니다.

검증 범위

직접 재현

검증일

검증 환경Unity 6000.5.3f1 (c2eb47b3a2a9), Windows 10 22H2 (10.0.19045) 64-bit, 기존 게임과 분리한 빈 프로젝트, Mono Editor, -batchmode -nographics -noUpm

Unity 6000.5.3f1 빈 프로젝트의 별도 Editor 프로세스 3회에서 문자열 경로와 Physics 쿼리를 직접 측정했습니다. 타임스탬프를 뺀 결과는 모두 같았습니다.