New RelicのMobile Agentを組み込むとアプリのクラッシュを取得することもできます。本ブログでは、クラッシュの解析に関するTipsを紹介します。

まず、iOSのアプリでは基本的にObjective-Cまたは、Swiftが利用されます。これらの言語により記述されたコードはコンパイラによりバイナリに変換されます。そのため、基本的にクラッシュデータには、関数のアドレスのみが格納され、シンボルファイル(dSYM)に含まれる情報とマッピング(シンボリケート)されることで、人が読むことができる形式のスタックトレースを表示することができます。もし、シンボリケートが行われていない場合、dSYMのアップロードが行われていないなどの可能性があるので、下記のページ等をご参照の上、ご対応ください。

以降は、dSYMがアップロードされ、シンボリケートができている前提で記載させていただきます。

Objective-Cの例外によるクラッシュ

通常、Objective-Cのコードで異常が発生した場合、NSExceptionまたは、その派生クラスの例外がthrowされます。コードによりcatchされ処理された場合はアプリは継続動作しますが、そのままthrowされた場合はアプリがクラッシュします。そのようにNSExceptionによって発生したクラッシュのデータは、スタックトレースの最初の2行に以下のような行が現れると思います。

NSException stack trace

また、その次の行以降にそのNSExceptionをthrowした関数やその呼び出し元の関数等が並びます。また、エラーの詳細の中のExceptionやMessageに格納されている値も合わせて確認していただくことで、原因となる箇所を特定していただける可能性があります。(以下はAgentのcrashNow()を呼び出した場合です。)

crashNow() summary

ゾンビオブジェクトによるクラッシュ

アプリの構造が複雑になっていくと、オブジェクトのインスタンス管理も複雑になります。そのため、すでに破棄されたオブジェクト(ゾンビオブジェクト)へアクセスしてしまい、クラッシュが発生することがあります。その場合、スタックトレースの最初の行に、 objc_msgSendobjc_retainobjc_release の関数が現れることが多くあります。例えばメインスレッド以外からUIの操作を行った、複数のスレッドからの利用があるけれどスレッドセーフに作っていなかった等の場合、こういったエラーが発生することがあります。こういったクラッシュが発生した場合、クラッシュが発生した関数でアクセスするオブジェクトのハンドリングについて見直してみてください。

zombie object stack trace

不正なメモリアクセスによるクラッシュ

前述のゾンビオブジェクトとは別に、不正なメモリアドレスへのアクセスもよくある問題です。こういった場合は、ExceptionにSIGSEGVが記録されると思います。よくあるケースではNULLポインタへアクセスするケースです。New Relicのクラッシュデータからはアクセス先のアドレス番地の確認はできませんが、他のクラッシュ同様にスタックトレースを確認していただくことができます。発生した関数を確認していただき、NULLや不正なアドレスへアクセスする可能性があるコードがないかを見直してみてください。

ios sigsegv

本ブログは、以下のApple社から提供されているドキュメントを元に、New RelicのUI上での見え方を踏まえ、よく発生する3つのケースを説明させていただきました。

Appleのサイトを参照いただくと、その他各種デバッグ関連の情報が記載されていますので、こちらもご参照の上、問題の解決に役立てて見てください。
https://developer.apple.com/documentation/xcode/diagnosing-issues-using-crash-reports-and-device-logs
 

なお、前述のクラッシュデータを確認しても、発生原因等にたどり着くのが難しい場合、イベント・トレイルを活用してみてください。自動で記録されたイベントやお客様が追加したパンくずが表示されるため、どういった経緯のあとにクラッシュしたかがわかり、よりクラッシュ発生のコンテキストを知ることができます。