TIL

트러블슈팅 - 레벨 전환/Restart 중 크래시 해결

think95592 2026. 6. 27. 21:42

트러블슈팅: 레벨 전환 및 Restart 중 크래시 발생

문제 상황

게임 플레이 중 레벨 전환이나 게임 오버 후 Restart를 누를 때 크래시가 발생했다.

버그 발생 영상: 

버그.mp4
2.77MB

원인 분석

처음에는 레벨 전환 과정에서 발생하는 문제라고 판단했다.

그래서 다음 부분들을 확인했다.

  • HUD Timer가 레벨 전환 후에도 실행되는지
  • OpenLevel 호출 순서
  • Widget 제거 여부
  • GameState와 PlayerController 생명주기
  • Timer 해제 여부

하지만 크래시는 계속 발생했고, Crash Log의 Call Stack을 확인한 결과 실제 원인은 AMineItem::Explode() 내부에 있었다.

```text
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION

AMineItem::Explode()

문제가 된 코드는 다음과 같았다.

 
GetWorld()->GetTimerManager().SetTimer(
    DestroyParticleTimerHandle,
    [Particle]()
    {
        Particle->DestroyComponent();
    },
    2.0f,
    false
);
 

지뢰 폭발 시 파티클을 생성하고, 2초 뒤 람다를 통해 직접 삭제하도록 구현했었다.

하지만 그 사이에 지뢰 액터가 Destroy되거나 레벨 전환이 발생하면, 람다가 이미 유효하지 않은 Particle을 참조하게 되어 크래시가 발생했다.

해결 방법

SpawnEmitterAtLocation()의 Auto Destroy 기능을 사용하도록 수정했다.

수정 전에는 파티클을 직접 Timer로 제거했다.

 
Particle = UGameplayStatics::SpawnEmitterAtLocation(
    GetWorld(),
    ExplosionParticle,
    GetActorLocation(),
    GetActorRotation(),
    false
);
 

수정 후에는 마지막 인자를 true로 설정하고, Timer 람다 코드를 제거했다.

 
UGameplayStatics::SpawnEmitterAtLocation(
    GetWorld(),
    ExplosionParticle,
    GetActorLocation(),
    GetActorRotation(),
    true
);
 

결과

수정 후 레벨 전환과 Restart 상황에서 크래시가 발생하지 않았다.

해결 영상:

버그해.mp4
15.52MB

배운 점

  • Timer와 Lambda를 사용할 때는 객체 생명주기를 반드시 고려해야 한다.
  • Destroy()나 OpenLevel() 이후에도 Timer가 실행될 수 있다.
  • UObject 계열 포인터를 람다로 캡처할 때는 특히 주의해야 한다.
  • 엔진에서 제공하는 Auto Destroy 기능을 활용하면 직접 객체를 제거하는 코드보다 안전하고 간단하다.
  • Crash Log와 Call Stack을 확인하면 실제 원인을 훨씬 빠르게 찾을 수 있다.