다음 정보를 사용하여 iOS 기기에서 Unity 애플리케이션을 실행할 때 자주 발생하는 충돌 및 기타 문제에 대한 해결 방법을 찾을 수 있습니다.
참고: 문제 해결 후에도 문제가 지속되면 iOS 충돌 버그 신고를 참조하십시오.
다음 목록에는 이 문제의 일반적인 이유가 나와 있습니다.
List<int>, List<SomeStruct>, List<SomeEnum>
Xcode 디버거 콘솔의 정보를 통해 이러한 문제를 발견할 수 있는 경우가 많습니다. View > Debug Area > Activate Console에서 디버거 콘솔에 액세스합니다.
이 메시지는 일반적으로 애플리케이션이 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 ()
이 메시지는 애플리케이션의 릴리스 빌드 동안 네이티브 심볼이 스트리핑되었음을 나타냅니다. 더 자세히 살펴보려면 다음 단계를 따라 전체 스택 추적에 액세스하십시오.
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 개발자).
메모리 사용량을 적게 유지하려면 다음 제안 사항을 사용하십시오.
사용 가능한 메모리의 양을 OS에 쿼리하는 것이 애플리케이션의 성능을 평가하는 가장 효율적인 방법일 수 있습니다. 하지만 OS가 많은 동적 버퍼와 캐시를 사용하므로 가용 메모리 통계는 신뢰하기 어렵습니다. 애플리케이션의 메모리 사용량을 추적하고, 특히 새 씬을 로드한 후 Xcode 메모리 툴과 함께 메인 지표로 사용하는 것이 좋습니다.
기기 로그를 검사하여 자세한 내용을 확인하는 것이 좋습니다. 그렇게 하려면 다음 단계를 따르십시오.
충돌 보고서도 조사해야 할 수 있습니다. 자세한 내용은 충돌 보고서 및 진단 로그 얻기를 참고하십시오(Apple 개발자).
iOS 애플리케이션이 첫 번째 프레임을 렌더링하고 입력을 처리할 수 있도록 시간 제한이 설정되어 있습니다. 애플리케이션이 이 제한을 초과하면 SpringBoard에서 종료됩니다. 예를 들어 첫 번째 씬의 크기가 너무 큰 애플리케이션에서 이러한 상황이 발생할 수 있습니다. 스플래시 화면으로 작은 초기 씬을 생성하고 몇 프레임 정도 기다린 다음 더 큰 씬을 로드하는 것이 좋습니다. 이렇게 하려면 다음 예시를 사용하십시오.
IEnumerator Start() {
yield return new WaitForEndOfFrame();
// Do not forget using UnityEngine.SceneManagement directive
SceneManager.LoadScene("Test");
}
.NET Cryptography 서비스는 관리되는 코드 스트리핑과 호환되지 않습니다. 이러한 서비스는 리플렉션에 의존하는 반면 관리되는 코드 스트리핑에는 정적 코드 분석이 포함됩니다. 스트리핑 프로세스는 Unity 프로젝트의 Assets 폴더에 커스텀 link.xml 파일을 추가하여 커스터마이즈할 수 있습니다. 이는 스트리핑에서 제외할 유형과 네임스페이스를 지정합니다. 이 문제를 해결하는 데 도움이 되도록 스트리핑 프로세스에서 System.Security.Crypography 네임스페이스를 제외합니다. 예를 들어 다음을 link.xml 파일에 추가합니다.
<linker>
<assembly fullname="mscorlib">
<namespace fullname="System.Security.Cryptography" preserve="all"/>
</assembly>
</linker>
이전 섹션에서 설명한 것과 동일한 방법으로 이 문제를 해결하거나, 스크립트 코드에 특정 클래스에 대한 레퍼런스를 추가할 수 있습니다. 그렇게 하려면 다음 예시를 사용하십시오.
object obj = new MD5CryptoServiceProvider();
UI 내 일부 작업으로 인해 iOS가 창을 즉시 다시 드로우합니다. 가장 일반적인 예시는 메인 UIWindow에 UIViewController가 있는 UIView를 추가하는 것입니다. 스크립트에서 네이티브 함수를 호출하는 경우 이는 Unity의 PlayerLoop 내에서 발생하며, PlayerLoop가 재귀적으로 호출됩니다. 이 경우 오류 메시지 PlayerLoop called recursively!가 표시됩니다. 이러한 경우에는 waitUntilDone이 false로 설정된 performSelectorOnMainThread(Apple 개발자) 메서드를 사용하는 것이 좋습니다. 그러면 Unity의 PlayerLoop 호출 사이에 작업을 실행하도록 예약할 것을 iOS에 알립니다.
이 문제를 진단하려면 다음 제안을 사용하십시오.
54997에서 멀티캐스트 브로드캐스트를 225.0.0.222로 만듭니다. 네트워크 설정에서 이 트래픽을 허용하는지 확인하십시오. 또한 프로파일러는 범위 55000 - 55511 내의 포트에 있는 원격 기기에 연결하여 기기에서 프로파일러 데이터를 가져옵니다. 이러한 포트는 TCP 액세스를 위해 열려 있어야 합니다.
이 문제는 빌드된 기계어 코드가 너무 크고 Xcode 제한에 도달했을 때 발생합니다. 이는 스크립트 코드가 많거나 빌드에서 대규모 외부 .NET 어셈블리를 사용하는 경우 발생할 수 있습니다. Script Debugging 빌드 설정을 사용하면 각 함수에 대한 추가 명령이 생성되므로 이 문제도 해결할 수 있습니다.
이 문제를 해결하려면 Unity 에디터에서 Edit > Project Settings > Player > iOS로 이동하여 다음 옵션 중 하나 이상을 시도하십시오.
문제가 계속 발생하면 사용자 스크립트 코드를 여러 어셈블리로 분할하는 것이 좋습니다. 예를 들어 이 위치의 코드가 다른 어셈블리에 추가되므로 Plugins 폴더를 사용하여 분할된 코드를 배치할 수 있습니다. 또한 특수 폴더 이름이 스크립트 컴파일에 미치는 영향에 대한 정보는 특수 폴더 및 스크립트 컴파일 순서를 참조하는 것이 좋습니다.
Xcode 버전 14.3부터 Apple은 Destination Architecture 옵션을 도입했습니다. Destination Architecture를 사용하면 Rosetta 시뮬레이터 모드에서 Xcode를 실행할 필요 없이 ARM 기반 Mac에서 iOS 시뮬레이터를 사용할 수 있습니다.
iOS 시뮬레이터를 보려면 다음 단계를 따르십시오.