Понимание дампа 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 больше не действителен.