36

必要以上に保持されているオブジェクトがあります(おそらくstrongの代わりにあるプロパティが原因ですweak)。コードベースが大きいため、場所を見つけるのは困難です。

ARCを使用しているときに、このオブジェクトが保持されているすべての行を見つけるにはどうすればよいですか?

retainARCを使用していなかった場合は、呼び出し元からオーバーライドして確認するだけでよいと思います。ARCで同様のことを行うことはできますか?

4

5 に答える 5

43

アプリケーションの成長を追跡するために、ヒープショット分析は非常に効果的であることが証明されています。これは、実際のリークと、リークによって割り当てが考慮されていないメモリの増加の両方をキャプチャします。

Allocationsインストゥルメントを使用して、すべての保持/解放イベントとそのバックトレースを確認できます。Allocationsインストゥルメントの小さな(i)ボタンを押して、「Recordreferencecounts」をオンにします。「アクティブな割り当てのみを追跡する」をオンにすると、Instrumentsによって収集されるデータの量が減り、より迅速になります(このコンテキストでは、デッドアロケーションはあまり役に立ちませんが、他のコンテキストでは役立つ可能性があります)。

これにより、(アドレスフィールドの右矢印をクリックして)任意の割り当てに飛び込み、すべての保持/解放イベントを確認し、それらが発生した場所を正確に確認できます。

ここに画像の説明を入力してください

于 2012-09-05T17:27:14.247 に答える
24

私は次のことを行うことで問題を見つけることができましたretain

  1. -fno-objc-arcオブジェクトクラスにコンパイラフラグを一時的に追加して、そのクラスのARCを無効にします。
  2. 一時的にオーバーライドしretain(を呼び出すだけsuper)、ブレークポイントを設定します。
  3. 呼び出されるたびに、呼び出しスタックをデバッグして確認しますretain
于 2012-09-04T13:34:49.940 に答える
11

先週、私は何人かの友人が彼らの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!
}
于 2012-09-04T12:30:32.540 に答える
5

この解決策は私にとっていくぶん役に立ちました。基本的に、メソッドスウィズリングを使用して、ARCコンパイラをだまして、保持と解放をオーバーライドしていないと思い込ませます。

#import <objc/runtime.h>
...
+ (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 %@",@((uintptr_t)[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 %@", @((uintptr_t)[self performSelector:NSSelectorFromString(@"retainCount")]));

    SEL selector = NSSelectorFromString(@"myrelease");
    return [self performSelector:selector withObject:nil];
#pragma clang diagnostic pop
}
于 2015-07-10T18:43:51.237 に答える
-3

ARCを使用している場合、保持を追加するオプションはありません。

secreenshot1

以下のオプションを使用してプロジェクトをARCに変換した場合、エラーが表示されます

スクリーンショット2

プロパティをとして設定した場合はstrong、プロジェクト全体でオブジェクトを1回割り当てる必要がありますself.yourobject = [[NSMutableArray alloc]init];。これに対する近道はありません。

于 2012-09-04T12:19:22.660 に答える