使用ARC查找保留的对象
我有一个被保留的东西超过了必要的(很可能是因为一个strong
而不weak
的属性)。 大的代码库,所以很难find在哪里。
如何在使用ARC时find所有保留这个对象的行?
如果我不使用ARC,我想我可以简单地覆盖retain
并检查它从哪里调用。 我可以做与ARC类似的东西吗?
为了跟踪应用程序的增长, Heapshot分析已被certificate是非常有效的。 它将捕获真正的泄漏和内存的增加,而这些泄漏并不是由分配造成的。
您可以使用Allocations工具查看所有保留/释放事件及其回溯。 按下Allocations仪器上的小(i)button,并打开“logging参考计数”。 打开“只跟踪活动分配”减less了仪器收集的数据量,使其更为快捷(在这种情况下,死区分配并不是真正有用的,但可以在其他情况下使用)。
这样,你可以进入任何分配(通过点击地址栏中的右箭头),查看所有保留/释放事件,并确切地看到他们发生的地方。
我设法通过执行以下操作来find有问题的retain
:
- 暂时将
-fno-objc-arc
添加到对象类Compiler Flags以禁用该类的ARC。 - 临时覆盖
retain
(只是调用super
),并在其上放置一个断点。 - 每次调用
retain
debugging并检查调用堆栈。
上周我帮助一些朋友在他们的ARC项目中debugging漏洞。 一些技巧:
1 /build立分析和启动仪器与泄漏检测。 然后探索当前分配的对象,find你想要的对象(你可以按名称对它们进行sorting),并查看它的保留/释放历史logging。 请注意,保留计数对ARC不是很有帮助。 你必须手动检查一步一步。
尝试评论所有可能成为泄漏源的代码,然后逐步取消注释。
2 /把一个NSLog
到你的init
和dealloc
以观察对象何时被创build和销毁。
3 /不要只看属性定义,看看是否手动实现属性设置器。 我在朋友的项目中发现了一个问题,如下所示:
@property (weak, nonatomic) id<...> delegate;
@interface ... { id<...> _delegate; } @synthesize delegate = _delegate; - (void)setDelegate(id<...>)delegate { _delegate = delegate; //with ARC this retains the object! }
这个解决scheme对我有些帮助。 它基本上使用方法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
}
如果您使用ARC,则永远不会获得添加保留的选项,
如果您使用下面的选项将项目转换为ARC,则会提示您input错误
如果你将属性设置为strong
,那么你应该在整个项目中分配一次对象,比如self.yourobject = [[NSMutableArray alloc]init];
。 这没有捷径。