9

Objective-cでリリース/割り当ての問題をデバッグする方法を尋ねたことがあれば、問題を追跡するのに役立つこれらの環境設定に出くわしたことでしょう。

  • NSZombieEnabled-リリース後もオブジェクトを保持するため、ポインタなどを取得できます。
  • MallocStackLogging-後で参照できるようにオブジェクトの履歴を保持します
  • NSDebugEnabled

これらはすべてYES、「実行可能ファイル」(グループツリーにあります)情報の「引数」タブの「環境」セクションで設定します。


だから、私はこのコンソール出力を取得しています

MyApp [ 4413:40b]-[CALayerretainCount]:割り当て解除されたインスタンス0x4dbb170に送信されたメッセージ

次に、デバッガーがブレークを転送して次のように入力している間に、ターミナルを開きます。

malloc_history 4413 0x4dbb170

次に、大きなテキストダンプを取得します。私が理解している限り、重要な点は次のとおりです。

1

ALLOC 0x4dbb160-0x4dbb171 [size=18]:
thread_a0375540 |start | main |
UIApplicationMain | GSEventRun |
GSEventRunModal | CFRunLoopRunInMode |
CFRunLoopRunSpecific | __CFRunLoopRun
| __CFRunLoopDoTimer |
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
| __NSFireDelayedPerform |
-[todoListViewController drillDocumentMenu:] |
-[documentListViewController drillIntoDocumentWithToDoRecord:] |
-[documentViewController OpenTodoDocument:OfType:WithPath:] |
-[documentViewController OpenDocumentOfType:WithPath:] |
-[documentViewController managePDFDocumentWithPath:] |
-[PDFDocument loadPDFDocumentWithPath:andTitle:] |
-[PDFDocument getMetaData] | CGPDFDictionaryApplyFunction |
ListDictionaryObjects(char const*,
CGPDFObject*, void*) | NSLog | NSLogv
| _CFLogvEx | __CFLogCString |
asl_send | _asl_send_level_message |
asl_set_query | strdup | malloc |
malloc_zone_malloc 

2

FREE  0x4dbb160-0x4dbb171 [size=18]:
thread_a0375540 |start | main |
UIApplicationMain | GSEventRun |
GSEventRunModal | CFRunLoopRunInMode |
CFRunLoopRunSpecific | __CFRunLoopRun
| __CFRunLoopDoTimer |
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
| __NSFireDelayedPerform |
-[todoListViewController drillDocumentMenu:] |
-[documentListViewController drillIntoDocumentWithToDoRecord:] |
-[documentViewController OpenTodoDocument:OfType:WithPath:] |
-[documentViewController OpenDocumentOfType:WithPath:] |
-[documentViewController managePDFDocumentWithPath:] |
-[PDFDocument loadPDFDocumentWithPath:andTitle:] |
-[PDFDocument getMetaData] | CGPDFDictionaryApplyFunction |
ListDictionaryObjects(char const*,
CGPDFObject*, void*) | NSLog | NSLogv
| _CFLogvEx | __CFLogCString |
asl_send | _asl_send_level_message |
asl_free | free

3

ALLOC 0x4dbb170-0x4dbb19f [size=48]:
thread_a0375540 |start | main |
UIApplicationMain | GSEventRun |
GSEventRunModal | CFRunLoopRunInMode |
CFRunLoopRunSpecific | __CFRunLoopRun
| __CFRunLoopDoTimer |
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
| __NSFireDelayedPerform |
-[todoListViewController drillDocumentMenu:] |
-[documentListViewController drillIntoDocumentWithToDoRecord:] |
-[documentViewController OpenTodoDocument:OfType:WithPath:] |
-[documentViewController OpenDocumentOfType:WithPath:] |
-[documentViewController managePDFDocumentWithPath:] |
-[ScrollViewWithPagingViewController init] | -[UIView init] |
-[UIScrollView initWithFrame:] | -[UIView initWithFrame:] | UIViewCommonInitWithFrame | -[UIView
_createLayerWithFrame:] | +[NSObject(NSObject) alloc] | +[NSObject(NSObject) allocWithZone:] | class_createInstance |
_internal_class_createInstanceFromZone | calloc | malloc_zone_calloc

私が理解していないのは、履歴がALLOC、FREE、ALLOCだった場合、なぜエラーはそれが解放されたことを示しているのですか(net +1 alloc)?

または、ダンプについての私の理解は間違っていますか?


編集(フレッシュラン=異なるオブジェクトポインタ):

機器によるゾンビ検出:

なぜ、どのように、保持カウントは1から-1にジャンプしますか?

ゾンビのバックトレースを見ると、保持カウントが呼び出されているように見えます:Quartzからrelease_root_if_unused


編集:解決済み-スーパーからビューを削除してから解放していました。放すだけで直ります。

4

2 に答える 2

2

@Kayは正しいです。malloc履歴は、指定されたアドレスで2つの割り当てを示しています。1つは割り当てられて解放され、もう1つはまだ使用されています。

必要なのは、すでにリリースされているretainCount上のへの呼び出しのバックトレースです。CALayerゾンビ検出が有効になっているため、特にメモリデバッグが有効になっているため、割り当て解除が行われていないか、行われない可能性があります。

malloc履歴とゾンビ検出を混在させると、実行時の動作が大幅に変わります。

Instrumentsでゾンビ検出を使用して実行することをお勧めします。うまくいけば、それは正確な問題を特定するでしょう。

そうでない場合は、ゾンビにメッセージが送信されたときにブレークするように設定できるブレークポイントがあります。そのブレークポイントを設定し、停止する場所を確認します。


OK-つまり、CoreAnimationは内部目的で保持カウントを使用しています(システムフレームワークはこれを回避できますが、壊れやすいです)。

-1は赤いニシンだと思います。ゾンビは保持カウントとして0xFF....FFFFを返す可能性があり、これはInstrumentsでは-1としてレンダリングされます。

次善の推測; これはタイマーで発生しているため、アニメーション中にオーバーリリースが発生している可能性があります。CoreAnimationレイヤーはこれを正しく処理する必要があります。コード内にビューまたはアニメーションレイヤーコンテナのオーバーリリースがあり、レイヤーが途中で消えてしまいます。

「ビルドと分析」を試しましたか?偶然に、それはどこかでビューの誤った管理を捕らえるかもしれません。

いずれにせよ、実験として、ビューを余分に保持して、この問題が解決するかどうかを確認してください。もしそうなら、それは少なくとも手がかりです。

(または、システムフレームワークのバグである可能性があります...多分...しかし疑わしいです。)

最後に、一体誰が呼んでいretainCountますか?!?!? CoreAnimationの場合retainCount、実装の詳細として内部的に使用されている可能性があります。

ただし、それがコードの場合は、ゾンビ呼び出しの場所がかなり明確になっているはずです。

于 2010-12-06T16:26:29.797 に答える
0

私は専門家ではありませんが、ブロック3の最初の行を見てください。

ALLOC 0x4dbb170 -0x4dbb19f [size = 48 ]:

他の2つの出力では、0x4dbb160-0x4dbb171のサイズ18のメモリブロックが割り当てられ、解放されました。古いオブジェクトが解放され、このメモリアドレスに新しいオブジェクトが存在すると思います。したがって、0x...b160の古いインスタンスは無効になります。

于 2010-12-06T13:36:22.177 に答える