Xcode4 のデバッグ環境を整える

SPECIAL


Xcode4 でメモリーリークを検出できるようにする

Xcode3 では何気なくできた Instruments による iPhone アプリのメモリーリークの検出ですけど、iOS 5 beta 5 の Xcode4 で作成したプロジェクトでそれをやろうとしてみたところ、何故だかなかなか上手く行きませんでした。

そこで、Xcode4 を用いてメモリーリークを検出する方法について説明したいと思います。

 

実行時にメモリーリークを確認できる Instruments というツールは、アプリを実行するときに、アップルメニューの【Product】から【Profile】を選択することで、起動させることができるようになっています。

このように Instruments を使ってアプリを実行するだけで、メモリーリークを検出できるようになっていると思います。

ただ、自分で試した限りでは、このようにすると malloc 等によるメモリーリークは随時検出されるものの、Objective-C の release 忘れについては検出されないような感じでした。

ちなみにメモリーリークの検出は、Debug スキームでも Release スキームでもできるようでしたけど、Instruments はときどきメモリーリークを検出できないこともあるようで、そんなときには Instruments をいったん終了してみたりしながら利用するなど、あまり過信しすぎないように利用するのが良さそうです。

 

なお、Objective-C の release 忘れのようなメモリーリークについては、ビルド時に(実行前に)検出できるようにもなっていました。

実行前にそれを検出させたい場合には、ビルドオプションで "Run Static Analyzer" を "Yes" に設定します。

左側のメニューからプロジェクト名をクリックして、となりの "PROJECT" グループでもプロジェクト名を選択すると、"Build Option" を設定できる画面が表示されます。

この中の "Run Static Analyzer" を "Yes" に設定します。

 

このようにすることで、スコープをコンパイラが追える程度の範囲であれば、コンパイル時に情報として、メモリーリークが発生したことを通知してくれるようになっていました。

色付けされる行がずれているのが気になりましたが、ともあれ指摘されている行番号は適切なもののようでしたので、これについてなら実行時に検出されなかったとしても、事前に気づいて修正することができそうですね。

ただ、クラスのメンバーとして持たせたオブジェクトなどについてはコンパイラでは検出してくれないようでした。

 

この感じから、実行時の Objective-C メモリーリークも検出できないようであれば、iOS 5 SDK から導入された Automatic Reference Counting (ARC) の機能を使って iPhone アプリを制作するのが、いちばん安心なのかもしれないですね。

 

Xcode4 で EXC_BAD_ACCESS の原因を探る

また、Xcode4 で特に何も対応しなかった場合、たとえば release 済みオブジェクトのプロパティを操作した時などに、次のようなエラーが発生する場合がありました。

Thread 1: Program received signal: "EXC_BAD_ACCESS".

ちなみにこれが検出されのは、問題を起こした行ではなく、それとは別のどこかのタイミングで発生するようです。

このメッセージには他に手掛かりになりそうな情報は含まれていないため、何かどこかでアクセス違反が発生したという程度しか把握できず、これではプログラムを修正しようにも困った感じです。

 

これを、Xcode4 ではスキームの設定を調整することで、原因箇所を検出することができるようになっていました。

そのためには、まずアップルメニューの【Product】から【Edit Scheme...】を選択します。

そして "Run" スキームの "Diagnostics" タブの中から "Enable Zombie Objects" を選択します。

こうすることで、実行時エラーが発生した際、発生したその場にとどまってプログラムが中断されて、たとえば次のようなメッセージが表示されるようになりました。

[UITextField setText:]: message sent to deallocated instance 0x652b420

プログラムの停止位置は、まさにこれが発生した行そのものでしたし、例えばこのメッセージを見れば、UITextField オブジェクトの Text プロパティを操作しようとしたときに、そのオブジェクトが既に release されていたということを知る手掛かりを得ることができました。