Найти, где объект хранится с помощью ARC
У меня есть объект, который сохраняется более чем необходимо (скорее всего, из-за свойства strong
вместо weak
). Большая база кода, поэтому трудно найти, где.
Как найти все строки, в которых этот объект сохраняется при использовании ARC?
Если бы я не использовал ARC, я бы мог просто переопределить retain
и проверить, откуда он вызвал. Могу ли я сделать что-то подобное с ARC?
Ответы
Ответ 1
Чтобы отслеживать рост приложения, Heapshot Analysis оказался очень эффективным. Он будет захватывать как истинные утечки, так и аккрецию памяти, где распределения не учитываются утечками.
Вы можете увидеть все события сохранения/выпуска и их обратную трассировку, используя инструмент Allocations. Нажмите маленькую (i) кнопку на инструменте "Распределения" и включите "Запись отсчетов". Включение "Только отслеживать активные распределения" уменьшает объем данных, собранных Инструментами, делая его более быстрым (и мертвые распределения в этом контексте не очень полезны, но могут быть и в других).
С этим вы можете погрузиться в любое распределение (щелкнув по правой стрелке в поле адреса), увидеть все события сохранения/выпуска и посмотреть, где именно они произошли.
![enter image description here]()
Ответ 2
Мне удалось найти оскорбление retain
, выполнив следующие действия:
- Временно добавить
-fno-objc-arc
к классу компилятора объекта.
для отключения ARC для этого класса.
- Временно переопределить
retain
(просто вызвать super
) и поставить на него контрольную точку.
- Отлаживать и проверять стек вызовов каждый раз, когда вызывается
retain
.
Ответ 3
На прошлой неделе я помогал друзьям отлаживать утечки в проекте ARC.
Некоторые советы:
1/Создание профилирования и запуск инструментов с обнаружением утечки. Затем исследуйте выделенные в данный момент объекты, найдите нужный объект (вы можете отсортировать их по имени) и загляните в историю сохранения/выпуска. Обратите внимание, что счет сохранения не очень помогает с ARC. Вы должны проверять его вручную шаг за шагом.
Попробуйте прокомментировать весь код, который может быть источником утечки, а затем раскомментировать его шаг за шагом.
2/Поместите a NSLog
в ваш init
и в dealloc
, чтобы наблюдать, когда объект был создан и уничтожен.
3/Не смотрите только на определения свойств, смотрите, если средства настройки свойств выполняются вручную. Я нашел проблему в проекте моих друзей следующим образом:
@property (weak, nonatomic) id<...> delegate;
@interface ... {
id<...> _delegate;
}
@synthesize delegate = _delegate;
- (void)setDelegate(id<...>)delegate {
_delegate = delegate; //with ARC this retains the object!
}
Ответ 4
Это решение было несколько полезно для меня. Он в основном использует метод swizzling для трюков компилятора ARC, думая, что вы не переопределяете сохранение и освобождение.
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class cls = [self class];
// When swizzling a class method, use the following:
// Class class = object_getClass((id)self);
SEL originalSelector1 = NSSelectorFromString(@"retain");
SEL swizzledSelector1 = NSSelectorFromString(@"myretain");
SEL originalSelector2 = NSSelectorFromString(@"release");
SEL swizzledSelector2 = NSSelectorFromString(@"myrelease");
Method originalMethod1 = class_getInstanceMethod(cls, originalSelector1);
Method swizzledMethod1 = class_getInstanceMethod(cls, swizzledSelector1);
Method originalMethod2 = class_getInstanceMethod(cls, originalSelector2);
Method swizzledMethod2 = class_getInstanceMethod(cls, swizzledSelector2);
BOOL didAddMethod1 =
class_addMethod(cls,
originalSelector1,
method_getImplementation(swizzledMethod1),
method_getTypeEncoding(swizzledMethod1));
if (didAddMethod1) {
class_replaceMethod(cls,
swizzledSelector1,
method_getImplementation(originalMethod1),
method_getTypeEncoding(originalMethod1));
} else {
method_exchangeImplementations(originalMethod1, swizzledMethod1);
}
BOOL didAddMethod2 =
class_addMethod(cls,
originalSelector2,
method_getImplementation(swizzledMethod2),
method_getTypeEncoding(swizzledMethod2));
if (didAddMethod2) {
class_replaceMethod(cls,
swizzledSelector2,
method_getImplementation(originalMethod2),
method_getTypeEncoding(originalMethod2));
} else {
method_exchangeImplementations(originalMethod2, swizzledMethod2);
}
});
}
-(id)myretain {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
NSLog(@"tracking retain now %d",(int)[self performSelector:NSSelectorFromString(@"retainCount")]);
SEL selector = NSSelectorFromString(@"myretain");
return [self performSelector:selector withObject:nil];
#pragma clang diagnostic pop
}
-(id)myrelease {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
NSLog(@"tracking release now %d",(int)[self performSelector:NSSelectorFromString(@"retainCount")]);
SEL selector = NSSelectorFromString(@"myrelease");
return [self performSelector:selector withObject:nil];
#pragma clang diagnostic pop
}
Ответ 5
Если вы используете ARC, вы никогда не получите возможность добавить сохранение,
![secreenshot1]()
и если вы преобразовали проект в ARC, используя нижеприведенный вариант, вам будет предложено с ошибкой
![screenshot2]()
Если вы установили свойство как strong
, вы должны выделить объект один раз через весь проект, например. self.yourobject = [[NSMutableArray alloc]init];
. Для этого нет ярлыка.