Version: Unity 6.0 (6000.0)
언어 : 한국어
iOS의 관리되는 스택 추적
iOS용 크래시 버그 보고서

iOS 기기 문제 해결

다음 정보를 사용하여 iOS 기기에서 Unity 애플리케이션을 실행할 때 자주 발생하는 충돌 및 기타 문제에 대한 해결 방법을 찾을 수 있습니다.

참고: 문제 해결 후에도 문제가 지속되면 iOS 충돌 버그 신고를 참조하십시오.

애플리케이션이 응답을 멈추고 Xcode가 상태 표시줄에 중단 표시됨

다음 목록에는 이 문제의 일반적인 이유가 나와 있습니다.

  • 초기화하지 않은 변수 등의 스크립팅 오류
  • Thumb 컴파일된 타사 네이티브 라이브러리 사용. 이러한 라이브러리는 iOS SDK 링커에서 알려진 문제를 트리거하고 무작위 크래시를 일으킬 수 있습니다.
  • 값 유형을 파라미터로 사용하는 일반 유형. 예: 직렬화된 스크립트 프로퍼티에 대한 List<int>, List<SomeStruct>, List<SomeEnum>
  • 관리되는 코드 스트리핑 활성화 시 반사 사용
  • 네이티브 플러그인 인터페이스 내 오류(관리되는 코드 메서드 서명이 네이티브 코드 함수 시그니처와 일치하지 않음)

Xcode 디버거 콘솔의 정보를 통해 이러한 문제를 발견할 수 있는 경우가 많습니다. View > Debug Area > Activate Console에서 디버거 콘솔에 액세스합니다.

Xcode 콘솔에 프로그램 수신 신호 표시: ‘SIGBUS’ 또는 EXC_BAD_ACCESS 오류

이 메시지는 일반적으로 애플리케이션이 NullReferenceException을 수신하면 iOS 기기에 표시됩니다. 네이티브 스택 추적을 사용하여 결함이 발생한 위치를 확인합니다.

네이티브 스택 추적은 결함을 조사하는 데 유용한 툴이지만 이를 사용하려면 일부 전문 지식이 필요합니다. 일반적으로 이러한 하드웨어 메모리 액세스 결함이 발생하고 나면 계속 진행할 수 없습니다. 네이티브 스택 추적에 액세스하려면 Xcode 디버거 콘솔에 bt all을 입력합니다. 오류가 발생한 위치에 대한 정보를 포함할 수 있으므로 출력된 스택 추적을 검사합니다. 예를 들어 일반적인 스택 추적은 다음과 같습니다.

...
Thread 1 (thread 11523): 

1. 0 0x006267d0 in m_OptionsMenu_Start ()
1. 1 0x002e4160 in wrapper_runtime_invoke_object_runtime_invoke_void__this___object_intptr_intptr_intptr ()
1. 2 0x00a1dd64 in mono_jit_runtime_invoke (method=0x18b63bc, obj=0x5d10cb0, params=0x0, exc=0x2fffdd34) at /Users/mantasp/work/unity/unity-mono/External/Mono/mono/mono/mini/mini.c:4487
1. 3 0x0088481c in MonoBehaviour::InvokeMethodOrCoroutineChecked ()
...

메인 스레드인 “Thread 1”에 대한 스택 추적을 찾습니다. 스택 추적의 첫 부분 라인은 오류가 발생한 위치를 가리킵니다. 이 예시에서 추적은 _OptionsMenu_ 스크립트의 _Start_ 메서드 내에서 NullReferenceException이 발생했음을 나타냅니다. 이 메서드 구현을 검사하면 문제의 원인을 파악하는 데 도움이 될 수 있습니다. 일반적으로 초기화 순서에 대한 잘못된 가정이 있을 때 NullReferenceExceptions는 _Start_ 메서드 내에서 발생합니다.

디버거 콘솔에 스택 추적의 일부만이 나타나는 경우도 있습니다. 예시:

Thread 1 (thread 11523): 

1. 0 0x0062564c in start ()

이 메시지는 애플리케이션의 릴리스 빌드 동안 네이티브 심볼이 스트리핑되었음을 나타냅니다. 더 자세히 살펴보려면 다음 단계를 따라 전체 스택 추적에 액세스하십시오.

  1. 기기에서 애플리케이션을 제거합니다.
  2. 모든 타겟을 클린합니다.
  3. Product > Run을 선택합니다.
  4. 앞서 설명한 대로 스택 추적을 가져옵니다.

Xcode 콘솔에 WARNING -> applicationDidReceiveMemoryWarning()이라는 메시지가 나타나고 그 후 애플리케이션이 즉시 충돌함

Program received signal: "0"과 같은 경고 메시지가 나타날 수 있습니다. 이 경고 메시지는 치명적이지 않은 경우가 많으며 iOS 메모리가 부족하다는 것을 나타냅니다. 일반적으로 메일과 같은 백그라운드 프로세스는 약간의 메모리를 확보하여 애플리케이션을 계속 실행할 수 있습니다. 하지만 애플리케이션이 계속 메모리를 사용하거나 더 많은 메모리를 요구하는 경우 iOS는 자체 애플리케이션을 포함하여 애플리케이션을 종료하기 시작합니다. Apple은 어느 정도의 메모리 사용량이 안전한지 문서화하지 않지만, 관찰 결과 전체 기기 RAM의 50% 미만을 사용하는 애플리케이션은 큰 메모리 사용량 문제가 없는 것으로 나타났습니다.

사용하는 주요 지표는 애플리케이션이 사용하는 RAM 양입니다. 애플리케이션 메모리 사용량은 다음 요소로 구성됩니다.

컴포넌트 설명
Application code OS는 애플리케이션 코드를 RAM에 로드하고 유지해야 하지만, 필요한 경우 일부를 폐기할 수 있습니다.
Native heap 엔진이 상태, 에셋 등을 RAM에 저장하는 데 사용합니다.
Managed heap il2cpp 런타임이 C# 오브젝트를 저장하는 데 사용합니다.
Metal memory pools 텍스처, 프레임 버퍼, 컴파일된 셰이더를 저장하는 데 사용합니다.

Xcode에서 애플리케이션 메모리 사용을 추적할 수 있습니다. 자세한 내용은 메모리 사용량 정보 수집을 참조하십시오(Apple 개발자).

메모리 사용량을 적게 유지하려면 다음 제안 사항을 사용하십시오.

  • 애플리케이션 바이너리 크기 줄이기: 가장 강력한 iOS 스트리핑 옵션을 사용하고 다른 .NET 라이브러리에 대한 불필요한 종속성을 피하십시오. 자세한 내용은 플레이어 설정 및 빌드된 iOS 플레이어의 크기 최적화를 참조하십시오.
  • 콘텐츠 크기 줄이기: 텍스처에 PVRTC 압축을 사용하고 로우 폴리 모델을 사용하십시오. 자세한 내용은 파일 크기 줄이기를 참조하십시오.
  • 스크립트에서 필요 이상의 메모리를 할당하지 않기: 프로파일러 창을 사용하여 모노 힙 크기 및 사용량을 추적합니다.

사용 가능한 메모리의 양을 OS에 쿼리하는 것이 애플리케이션의 성능을 평가하는 가장 효율적인 방법일 수 있습니다. 하지만 OS가 많은 동적 버퍼와 캐시를 사용하므로 가용 메모리 통계는 신뢰하기 어렵습니다. 애플리케이션의 메모리 사용량을 추적하고, 특히 새 씬을 로드한 후 Xcode 메모리 툴과 함께 메인 지표로 사용하는 것이 좋습니다.

애플리케이션이 Xcode에서 올바르게 실행되지만 기기에서 첫 번째 씬을 로드할 때 충돌이 발생함

기기 로그를 검사하여 자세한 내용을 확인하는 것이 좋습니다. 그렇게 하려면 다음 단계를 따르십시오.

  1. 타겟 기기를 macOS 기기에 연결합니다.
  2. Xcode에서 Window > Devices and Simulators를 선택합니다.
  3. 창의 왼쪽 툴바에서 타겟 기기를 선택합니다.
  4. Show the device console을 클릭하고 최신 메시지를 검토합니다.

충돌 보고서도 조사해야 할 수 있습니다. 자세한 내용은 충돌 보고서 및 진단 로그 얻기를 참고하십시오(Apple 개발자).

Xcode Organizer 콘솔에 Killed by SpringBoard 메시지가 나타남

iOS 애플리케이션이 첫 번째 프레임을 렌더링하고 입력을 처리할 수 있도록 시간 제한이 설정되어 있습니다. 애플리케이션이 이 제한을 초과하면 SpringBoard에서 종료됩니다. 예를 들어 첫 번째 씬의 크기가 너무 큰 애플리케이션에서 이러한 상황이 발생할 수 있습니다. 스플래시 화면으로 작은 초기 씬을 생성하고 몇 프레임 정도 기다린 다음 더 큰 씬을 로드하는 것이 좋습니다. 이렇게 하려면 다음 예시를 사용하십시오.

IEnumerator Start() {
    yield return new WaitForEndOfFrame();
// Do not forget using UnityEngine.SceneManagement directive
    SceneManager.LoadScene("Test");
}

System.Security.Cryptography와 관리되는 코드 스트리핑을 함께 사용할 경우 기기에서 충돌 발생

.NET Cryptography 서비스는 관리되는 코드 스트리핑과 호환되지 않습니다. 이러한 서비스는 리플렉션에 의존하는 반면 관리되는 코드 스트리핑에는 정적 코드 분석이 포함됩니다. 스트리핑 프로세스는 Unity 프로젝트의 Assets 폴더에 커스텀 link.xml 파일을 추가하여 커스터마이즈할 수 있습니다. 이는 스트리핑에서 제외할 유형과 네임스페이스를 지정합니다. 이 문제를 해결하는 데 도움이 되도록 스트리핑 프로세스에서 System.Security.Crypography 네임스페이스를 제외합니다. 예를 들어 다음을 link.xml 파일에 추가합니다.

<linker>
       <assembly fullname="mscorlib">
               <namespace fullname="System.Security.Cryptography" preserve="all"/>
       </assembly>
</linker>

System.Security.Cryptography.MD5와 관리되는 코드 스트리핑을 함께 사용할 경우 애플리케이션이 충돌

이전 섹션에서 설명한 것과 동일한 방법으로 이 문제를 해결하거나, 스크립트 코드에 특정 클래스에 대한 레퍼런스를 추가할 수 있습니다. 그렇게 하려면 다음 예시를 사용하십시오.

object obj = new MD5CryptoServiceProvider();

네이티브 함수를 통해 Cocoa를 사용할 때 PlayerLoop called recursively! 오류 메시지가 표시됨

UI 내 일부 작업으로 인해 iOS가 창을 즉시 다시 드로우합니다. 가장 일반적인 예시는 메인 UIWindow에 UIViewController가 있는 UIView를 추가하는 것입니다. 스크립트에서 네이티브 함수를 호출하는 경우 이는 Unity의 PlayerLoop 내에서 발생하며, PlayerLoop가 재귀적으로 호출됩니다. 이 경우 오류 메시지 PlayerLoop called recursively!가 표시됩니다. 이러한 경우에는 waitUntilDonefalse로 설정된 performSelectorOnMainThread(Apple 개발자) 메서드를 사용하는 것이 좋습니다. 그러면 Unity의 PlayerLoop 호출 사이에 작업을 실행하도록 예약할 것을 iOS에 알립니다.

프로파일러 또는 디버거가 애플리케이션에 액세스할 수 없음

이 문제를 진단하려면 다음 제안을 사용하십시오.

  • 개발용 빌드를 구축하고 Script DebuggingAutoconnect Profiler를 활성화했는지 확인하십시오. 이러한 프로퍼티에 대한 자세한 내용은 iOS 빌드 설정 레퍼런스를 참조하십시오.
  • 기기에서 실행되는 애플리케이션은 UDP 포트 54997에서 멀티캐스트 브로드캐스트를 225.0.0.222로 만듭니다. 네트워크 설정에서 이 트래픽을 허용하는지 확인하십시오. 또한 프로파일러는 범위 55000 - 55511 내의 포트에 있는 원격 기기에 연결하여 기기에서 프로파일러 데이터를 가져옵니다. 이러한 포트는 TCP 액세스를 위해 열려 있어야 합니다.

Xcode가 ARM64 branch out of range (<value> max is +/–128MB) 오류를 표시함

이 문제는 빌드된 기계어 코드가 너무 크고 Xcode 제한에 도달했을 때 발생합니다. 이는 스크립트 코드가 많거나 빌드에서 대규모 외부 .NET 어셈블리를 사용하는 경우 발생할 수 있습니다. Script Debugging 빌드 설정을 사용하면 각 함수에 대한 추가 명령이 생성되므로 이 문제도 해결할 수 있습니다.

이 문제를 해결하려면 Unity 에디터에서 Edit > Project Settings > Player > iOS로 이동하여 다음 옵션 중 하나 이상을 시도하십시오.

  • Strip Engine Code를 활성화합니다.
  • 더 높은 Managed Stripping Level을 사용합니다.
  • IL2CPP Code GenerationFaster (smaller) Builds로 설정합니다.

문제가 계속 발생하면 사용자 스크립트 코드를 여러 어셈블리로 분할하는 것이 좋습니다. 예를 들어 이 위치의 코드가 다른 어셈블리에 추가되므로 Plugins 폴더를 사용하여 분할된 코드를 배치할 수 있습니다. 또한 특수 폴더 이름이 스크립트 컴파일에 미치는 영향에 대한 정보는 특수 폴더 및 스크립트 컴파일 순서를 참조하는 것이 좋습니다.

Xcode 14.3을 실행하는 ARM 기반 Mac에서 iOS 시뮬레이터가 보이지 않음

Xcode 버전 14.3부터 Apple은 Destination Architecture 옵션을 도입했습니다. Destination Architecture를 사용하면 Rosetta 시뮬레이터 모드에서 Xcode를 실행할 필요 없이 ARM 기반 Mac에서 iOS 시뮬레이터를 사용할 수 있습니다.

iOS 시뮬레이터를 보려면 다음 단계를 따르십시오.

  1. Xcode 메뉴 바에서 Product > Destination > Destination Architectures를 선택합니다.
  2. Apple Silicon 아키텍처와 Rosetta 아키텍처 모두에 대한 iOS 시뮬레이터를 보려면 Show Rosetta Destinations를 선택하거나, Show Both를 선택합니다.

추가 리소스

iOS의 관리되는 스택 추적
iOS용 크래시 버그 보고서