Есть ли способ "найти тайну"?
Недавно я исправлял код. Был большой класс, который бы не освободил. Вам нужно будет ударить его 5 или 6 релизами, чтобы получить его dealloc.
Я внимательно просмотрел большой класс и в конце концов нашел различные вещи, которые нужно было освободить.
Это заставило меня подумать: просто должен быть какой-то действительно простой способ "найти" все сохраненные объекты на объекте. Я прав?
Итак, есть ли простой способ найти все сохраненные объекты на объекте? Есть ли кнопка в XCode или инструментах, о которых все знают?
Что вы делаете, когда не можете найти такую тайну?
Итак, в юниверсе iOS, если кто-нибудь знает "Показывать, где все сохраненные данные появились на этом объекте" - спасибо!
P.S. Обратите внимание, что утечки нет, и этот вопрос полностью не связан с утечками. Объект просто "совершенно правильно" не будет выпускаться.
Позже..
Поистине поразительное решение от Fabio:
Фабио предоставил удивительное решение этой проблемы. В девяти словах, вот он:
-(id)retain
{
NSLog(@"%@", [NSThread callStackSymbols]);
return ([super retain]);
}
Это удивительно полезно во многих ситуациях и приводит ко многим другим полезным вещам. Вероятно, вы сохранили мне две человеко-недели работы в год, Фабио. Спасибо!
Кстати, если вы просто справляетесь с этим и боретесь с выходом, я видел, что обычно будет много фрагментов с участием "UINib instantiateWithOwner:". Похоже, что они придут на первое место, за ними последуют значительные куски.
Ответы
Ответ 1
Просто гадать... но вы можете перезаписать метод сохранения пользовательского вызова класса super и бросить хороший NSLog для печати стека вызовов.
Обновить с помощью фактического кода от Joe
-(id) retain {
NSLog(@"%@", [NSThread callStackSymbols]);
return ([super retain]);
}
Еще одна важная деталь: [NSThread callStackSymbols] возвращает NSArray из NSStrings, который может быть отфильтрован и использован для других целей. Например, в сложном и динамическом коде, чтобы проверить, правильно ли метод вызывает другой.
Примечание:
В среде ARC вам нужно будет сначала добавить флаги -fno-objc-arc
в компилятор, чтобы вы могли переопределить сохранение и вызов super.
Ответ 2
Инструменты могут отображать стек вызовов для каждого malloc, выпускать и сохранять для любого объекта Obj-C в приложении без необходимости изменения кода. Он работает, когда вы используете ARC, что не относится к решению от fabio.
Это действительно полезно для поиска сохранности этих загадок - например, когда объект просто не будет отменен, если это необходимо.
Вот как:
- CMD + I (Продукт/Профиль)
- Когда инструменты появляются, выберите "Выделения" (NOT Leaks).
- Ваше приложение должно работать.
- Делайте все, что заставляет вас скрывать вашу тайну.
- Выберите инструмент "Выделение" на левой панели.
- Нажмите CMD + 1 или выберите круг с волной в нем справа. В панели справа внизу отметьте опцию "Record reference counts". Это важно, или будут записаны только mallocs и frees.
- В окне поиска в правом верхнем углу списка введите имя своего класса (например, BCMyObject).
- Это фильтрует список "Статистика" , чтобы показать, сколько экземпляров вашего класса в настоящее время проживает. Столбец #Persistent показывает, сколько экземпляров живут.
- Нажмите строку, а затем маленькую стрелку → рядом с именем класса. Вы увидите, что в панировочных сухарях отображается "Статистика" > "Сводка распределения" > "BCMyobject"
- Это показывает вам все экземпляры указанного класса (и какие из них живут).
- Выберите экземпляр и снова щелкните стрелку (на этот раз по адресу)
- Теперь вы увидите "Статистика" > "Сводка распределения" > "BCMyObject > History: 0xADDRESS" в breadcrumps.
- Это будет отображаться каждый раз, когда объект malloc'd сохраняется или освобождается.
- Теперь на левой панели, где была опция "Record Reference Counts", нажмите значок, который выглядит как панель с прикрепленными к ней ящиками или нажмите CMD + 3.
- Выберите одну из строк, и вы увидите полный стек вызовов, который привел к вызову.
Легко! (МОГ)
Ответ 3
Поместите контрольную точку на пользовательский класс "Сохранить
Вы можете установить символическую точку останова при сохранении, а затем установить ее на метод сохранения пользовательского класса. Проблема здесь в том, что сохранение - это метод на NSObject
, поэтому при размещении точки останова вы получите выбор всех классов objective-c.
В этом случае было бы лучше перезаписать метод сохранения пользовательского класса вызовом super, поэтому он ничего не сделал бы, кроме как вы могли бы разместить в нем точку останова.
Используйте действие точки останова для регистрации вызывающего абонента
Чтобы добавить действие точки останова, дважды нажмите на синий маркер. Найдите точку останова в списке и нажмите кнопку + справа. Затем выберите Debugger command
и добавьте в это поле команду GDB frame 1
, которая покажет вам вызывающего абонента. Таким образом, вы сохраняете холодный журнал, и откуда они берутся. При регистрации релизов аналогичным образом вы можете проверить, что такое дополнительный выпуск.
Это все еще немного утомительно, но это лучшее, что я могу придумать.
Ответ 4
Инструменты и управление памятью - ваш друг. Утечки и зомби - два из самых ценных инструментов. Используйте их.
Продукт → Профиль (или Cmd-I)
Ответ 5
К сожалению, нелегко программно определить, что "принадлежит" объекту, поскольку идея "владение объектами" - это соглашение о кодировании (если вы не разрешаете сборку мусора).
Часто используется стоп-каротаж (обычно я использую несколько точек останова с bt;continue
), но это говорит только о функции, которая называется удержание, а не о "увеличенной картине" (например, вы можете "передать право собственности" с помощью [ivar2 release]; ivar2 = ivar1; ivar1 = nil;
), Иногда это утечка UIKit, поэтому у вас нет исходного кода, и вам действительно нужно копать.
Если это не утечка, вызовите -release
несколько раз и посмотрите, где он сработает!
Ответ 6
Попробуйте использовать "Сборка и анализ" в Xcode?
Это отлично подходит для того, чтобы получить доступ к нижней части объектов.