Понимание дампа malloc_history

Если вы когда-нибудь спрашивали, как я могу отладить проблемы с выпуском / выделением ресурсов в target-c, вы натолкнулись на следующие параметры среды, которые могут помочь отследить проблему:

  • NSZombieEnabled - Держит ругательства вокруг после выпуска, так что вы можете получить указатели и т. Д.
  • MallocStackLogging - сохраняет историю объекта для последующего использования
  • NSDebugEnabled

Вы устанавливаете все это YES в разделе "среда" вкладки "аргументы" в информации о "исполняемых файлах" (находится в дереве групп).


Итак, я получаю этот вывод консоли

MyApp [ 4413: 40b] - [CALayer retainCount]: сообщение отправлено освобожденному экземпляру 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?

Глядя на след Зомби, похоже, что счет сохранения вызывается: Кварц через release_root_if_unused


Редактировать: Решено - я удалял вид из супер, затем выпускал его. Исправлено, просто выпуская его.

2 ответа

Решение

@ Кей правильно; история malloc показывает два размещения по указанному адресу; тот, который был распределен и освобожден, и тот, который все еще в игре.

Что вам нужно, это обратный след вызова retainCount на CALayer это уже было выпущено. Поскольку у вас включено обнаружение зомби, помимо прочего, может случиться так, что освобождение просто не произошло и не произойдет.

Смешение истории malloc с обнаружением зомби значительно меняет поведение во время выполнения.

Я бы посоветовал работать с обнаружением зомби в инструментах Надеюсь, это точно определит проблему.

Если нет, то есть точка останова, которую вы можете установить, чтобы сломать, когда зомби обмениваются сообщениями. Установите эту точку останова и посмотрите, где вы остановитесь.


Итак, CoreAnimation использует счет сохранения для внутренних целей (системные фреймворки могут с этим справиться, хотя и хрупкими).

Я думаю, что -1 - красная сельдь; вполне вероятно, что зомби вернут 0xFF....FFFF в качестве сохраняемого счетчика, и в инструментах это отображается как -1.

Следующее лучшее предположение; поскольку это происходит по таймеру, переиздание, вероятно, происходит во время анимации. Слои CoreAnimation должны обрабатывать это правильно. В вашем коде есть чрезмерный выпуск контейнера слоя представления или анимации, из-за которого слой преждевременно исчезает.

Вы пробовали "Построить и проанализировать"? Неслучайно это могло бы поймать неумелое управление представлением где-нибудь.

В любом случае и в качестве эксперимента попробуйте сохранить ваши представления в течение дополнительного времени и посмотреть, остановит ли это эту проблему. Если это так, то это, по крайней мере, ключ.

(Или это может быть ошибка в системных рамках... может быть... но сомнительно.)

Наконец, кто, черт возьми, зовет retainCount ?!?!? В случае CoreAnimation возможно, что retainCount используется внутри как деталь реализации.

Если это ваш код, тогда местоположение вызова зомби должно быть довольно очевидным.

Я не эксперт, но если вы посмотрите на первую строку в блоке 3:

ALLOC 0x4dbb170-0x4dbb19f [размер =48]:

В то время как в двух других выходах блок памяти размером 18x0dbb160-0x4dbb171 был выделен и освобожден. Я предполагаю, что старый объект был освобожден, и по этому адресу памяти находится новый объект. Таким образом, старый экземпляр в 0x...b160 больше не действителен.

Другие вопросы по тегам