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 コンソールが、Program received signal:“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 コンソールに、applicationDidReceiveMemoryWarning() の警告が表示され、アプリケーションがクラッシュする

Program received signal: "0" などの警告メッセージが表示される場合があります。この警告メッセージは、多くの場合は致命的ではなく、iOS のメモリが不足していることを示しています。一般的には、メールのようなバックグラウンドプロセスでいくつかのメモリが解放され、アプリケーション実行が継続されます。ただし、アプリケーションが引き続きメモリを使用したり、メモリの追加を要求したりすると、iOS はそれ自体を含むアプリケーションの終了を開始します。Apple は安全なメモリ使用量についてのドキュメントを提供していませんが、使用量がデバイス RAM 全体の 50% 未満のアプリケーションでは、メモリ使用量に大きな問題が発生しないことが観察から示されています。

使用する主な指標は、アプリケーションの RAM 使用量です。アプリケーションのメモリ使用量は、以下の部分で構成されています。

Component 説明
アプリケーションコード OS は RAM にアプリケーションコードをロードし、保持する必要がありますが、実際には、必要な場合に一部が廃棄されることがあります。
ネイティブヒープ エンジンの状態とユーザーのアセットを RAM に格納するために、エンジンによって使用されます。
マネージヒープ C# オブジェクトを格納するために il2cpp ランタイムによって使用されます。
Metal メモリプール テクスチャ、フレームバッファ、コンパイルされたシェーダーを格納するために使用されます。

Xcode でアプリケーションメモリの使用状況を追跡できます。詳細は、Gathering information about memory use (Apple Developer) を参照してください。

メモリ使用量を低く抑えるには、以下の推奨事項を実施します。

  • アプリケーションのバイナリサイズを小さくします。iOS のもっとも強力なストリッピングオプションを使用し、さまざまな .NET ライブラリの不要な依存関係を避けてください。詳細については、プレイヤー設定およびビルドした iOS プレイヤーのサイズ最適化を参照してください。
  • コンテンツのサイズを小さくしてください。テクスチャに PVRTC 圧縮を使用し、ローポリゴンモデルを使います。詳細については、ファイルサイズの削減を参照してください。
  • スクリプトに必要以上にメモリを割り当てないでください。Profiler ウィンドウで Mono のヒープサイズと使用状況を追跡します。

空きメモリの量について OS に照会することは、アプリケーションのパフォーマンスを評価する効率的な方法のように思えるかもしれません。しかし、OS はダイナミックバッファとキャッシュを多く使用しているので、空きメモリの統計は信頼できない傾向があります。アプリケーションのメモリ消費を追跡し、特に新しいシーンをロードした後は、このメモリ消費量を主な指標とし、Xcode メモリツールと組み合わせて使用することを推奨します。

アプリケーションは Xcode から正しく起動するが、デバイス上の最初のシーンのロード中にクラッシュする

デバイスのログを調べて詳細を確認することを推奨します。このためには、以下のステップを実施してください。

  1. ターゲットデバイスを macOS デバイスに接続します。
  2. Xcode から、Window > Devices and Simulators を選択します。
  3. ウィンドウの左側のツールバーでターゲットデバイスを選択します。
  4. Show the device console をクリックし、最新のメッセージを確認します。

クラッシュレポートも調べる必要があるかもしれません。詳細は、Acquiring crash reports and diagnostic logs (Apple Developer) を参照してください。

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 暗号化サービスは、マネージコードストリッピングと互換性がありません。これらのサービスはリフレクションに依存しますが、マネージコードストリッピングには静的コード分析が含まれています。ストリッピングプロセスは、カスタムの link.xml ファイルを Unity プロジェクトの Assets フォルダーに加えてカスタマイズできます。これにより、ストリッピングから除外するタイプと名前空間を指定できます。ストリッピングプロセスから 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 がすぐにウィンドウを再描画することになります。特に一般的な例は、UIViewController を持つ UIView を、メインの UIWindow に追加する操作です。スクリプトからネイティブ関数を呼び出すと、Unity の PlayerLoop 内部でその呼び出しが発生するため、結果として PlayerLoop が再帰的に呼び出されることになります。これが発生すると、エラーメッセージ PlayerLoop called recursively! を受け取ることになります。このような場合、waitUntilDonefalse に設定したうえでの performSelectorOnMainThread (Apple Developer) メソッドの使用を検討してください。これにより、Unity の PlayerLoop 呼び出しの間に実行すべき処理をスケジュールするように、iOS に通知されます。

プロファイラーまたはデバッガーがアプリケーションにアクセスできない

この問題を診断するには、以下の推奨事項を実施してください。

  • 開発ビルドを構築してスクリプトデバッグを有効にし、自動接続プロファイラーを有効にしたことを確認します。これらのプロパティの詳細については、iOS ビルド設定のリファレンスを参照してください。
  • デバイス上で動作するアプリケーションは、UDP ポート 54997225.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 に移動し、以下のオプションを 1 つ以上試してください。

  • Strip Engine Code を有効にします。
  • マネージストリッピングレベルをより高くします。
  • IL2CPP Code GenerationFaster (smaller) Builds に設定します。

問題が解決しない場合は、ユーザースクリプトコードを複数のアセンブリに分割することをお勧めします。例えば、Plugins フォルダーを使用して、この場所のコードが別のアセンブリに追加されるときに、任意の分割コードを配置できます。また、特殊フォルダー名がスクリプトのコンパイルに与える影響については、特殊フォルダーとスクリプトのコンパイル順を参照してください。

Xcode 14.3 を実行する ARM ベースの Mac で iOS シミュレーターが表示されない

Apple は Xcode バージョン 14.3 から、Destination Architecture オプションを導入しました。Destination Architecture では、ARM ベースの Mac で iOS シミュレーターを使用するために、Rosetta シミュレーターモードで Xcode を実行する必要がありません。

iOS シミュレーターを表示するには、以下のステップを行います。

  1. Xcode メニューバーで、Product > Destination > Destination Architectures を選択します。
  2. Show Rosetta Destinations または Show Both を選択すると、Apple シリコンと Rosetta の両方のアーキテクチャの iOS シミュレーターが表示されます。

追加リソース

iOS のマネージスタックトレース
iOS のクラッシュバグのレポート