查找ARC保留对象的位置

时间:2012-09-04 11:17:22

标签: ios xcode macos automatic-ref-counting

我有一个被保留的对象超过必要(很可能是由于strong而不是weak的属性)。大代码库,所以很难找到。

如何在使用ARC时找到保留此对象的所有行?

如果我没有使用ARC,我想我可以简单地覆盖retain并检查它的调用位置。我可以用ARC做类似的事情吗?

5 个答案:

答案 0 :(得分:42)

为了跟踪应用程序的增长,Heapshot Analysis已证明非常有效。它将捕获真正的泄漏和内存增加,其中分配不会泄漏。

您可以使用Allocations工具查看所有保留/释放事件及其回溯。点击Allocations仪器上的小(i)按钮,然后打开“记录参考计数”。打开“仅跟踪活动分配”会减少Instruments收集的数据量,使其更加快速(并且死分配在此上下文中并不真正有用,但可以在其他情况下使用)。

通过这种方式,您可以深入了解任何分配(通过单击地址字段中的右箭头),查看所有保留/释放事件并查看它们的确切位置。

enter image description here

答案 1 :(得分:24)

通过执行以下操作,我设法找到了有问题的retain

  1. 暂时将-fno-objc-arc添加到对象类Compiler Flags 禁用该类的ARC。
  2. 暂时覆盖retain(只需致电super)并在其上设置断点。
  3. 每次调用retain时调试并检查调用堆栈。

答案 2 :(得分:10)

上周我帮助一些朋友在他们的ARC项目中调试泄漏。 一些提示:

1 /构建用于分析并启动具有泄漏检测的仪器。然后浏览当前分配的对象,找到所需的对象(可以按名称对它们进行排序)并查看其保留/释放历史记录。请注意,保留计数对ARC没有多大帮助。您必须一步一步地手动检查。

尝试评论可能是泄漏源的所有代码,然后逐步取消注释。

2 /将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!
}

答案 3 :(得分:3)

这个解决方案对我有点帮助。它基本上使用方法调配来欺骗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

}

答案 4 :(得分:-3)

如果您使用ARC,则永远不会选择添加retain,

secreenshot1

如果您使用以下选项将项目转换为ARC,系统将提示您输入错误

screenshot2

如果您已将该属性设置为strong,那么您应该在整个项目中分配一次对象,例如self.yourobject = [[NSMutableArray alloc]init];。这没有捷径。