내배캠 TIL

[내배캠 TIL 260203] Unreal Engine 타이머, 람다식, UObject 수명 관리 이슈

xodn246 2026. 2. 3. 20:51

문제 상황

언리얼에서 지뢰 아이템(AMineItem)을 구현하던 중, 일정 시간이 지난 뒤 폭발하도록 FTimerManager를 사용했다.
게임 실행 중 다음과 같은 크래시가 발생했다.

EXCEPTION_ACCESS_VIOLATION reading address 0xffffffffffffffff

콜스택을 확인해보니 FTimerManager::Tick()에서 호출된 람다 함수 내부에서 문제가 발생했다.


원인 분석

문제의 핵심은 타이머 + 람다식 + UObject 수명 관리였다.

 
GetWorld()->GetTimerManager().SetTimer( 
    DestroyParticleTimerHandle, 
    [Particle]() 
    { 
       Particle->DestroyComponent(); 
    }, 
    2.0f, 
    false );
  • 람다식이 UParticleSystemComponent* 포인터를 직접 캡처하고 있음
  • 타이머는 2초 뒤 실행됨
  • 그 사이에
    • 액터가 Destroy() 됨
    • 월드 정리 또는 GC 발생 가능
  • 이미 파괴된 UObject에 접근하면서 Access Violation 발생

람다식은 UObject의 생명주기를 인식하지 못하기 때문에, 이미 해제된 메모리를 접근할 위험이 있다.


해결 방법  – TWeakObjectPtr 사용

람다식에서 UObject를 직접 잡지 않고, TWeakObjectPtr로 감싸 유효성 체크를 추가했다.

 
if (Particle)
{
    TWeakObjectPtr<UParticleSystemComponent> WeakParticle = Particle;

    FTimerHandle DestroyParticleTimerHandle;
    GetWorld()->GetTimerManager().SetTimer(
        DestroyParticleTimerHandle,
        [WeakParticle]()
        {
            if (WeakParticle.IsValid())
            {
                WeakParticle->DestroyComponent();
            }
        },
        2.0f,
        false
    );
}
  • GC로 객체가 제거되면 IsValid()가 false
  • 이미 파괴된 UObject 접근 방지
  • 크래시 발생하지 않음