質問

何かを明確にしたかった。

次のコードがあるとしましょう。

- (void) viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  for (int i = 0; i < 5000000; i++) {
    NSString *s = [NSString stringWithFormat:@"Hello, %@!", @"World"];
  }
}

これにより、この関数呼び出し内に500万個の自動リリースされた文字列が作成されます。私が見た唯一の@autoreleasepoolは、main.mでアプリケーションのインスタンス化を包む@autoreleasepoolであるため、アプリケーションの終了までこれらのオブジェクトを保持することを期待していました。しかし、そうではありません。この関数呼び出しの最後に、彼らはすべてリリースを呼び出し、メモリから削除されているようです。

このドキュメント:

https://developer.apple.com/library/mac/documentation/cocoa/reference/foundation/classes/nsautoreleasepool_class/reference/reference.html

「アプリケーションキットは、イベントループのすべてのサイクルの開始時にメインスレッドにオートレリーズプールを作成し、最後にそれを排出するため、イベントの処理中に生成されたオートリリースオブジェクトをリリースします。」

それは私にとって理にかなっていますが、これはuikitの下にあり、アプリケーションキットではありません。私の質問は、Uikit/Cocoa Touchがこの場合も同じことをしているのですか、それとも私のオブジェクトがリリースされる別の説明がありますか?

ありがとう!

役に立ちましたか?

解決 2

はい、uikitは同じことをします。システムが作成したメインスレッドAutoreleaseプールは、すべての実行ループサイクルの終わりに排出されます。おそらく、あなた自身のコードでこの正確な寿命に頼らないことが最善です。手動で新しいスレッドを作成する場合(EG NSTHREADを使用)、そのスレッドでAutorEleaseプールを作成する責任があります。

編集:ロブの回答は、ARCの下での行動に関するいくつかの良い追加情報を提供します。一般的に、アークが行うことができる最適化のために、オブジェクトがオートレリーズプールで終わる可能性が低いと言うのは公平です。

他のヒント

アンドリューは、あなたの主な質問に答えました。はい、あなたのオートリリースプールはメインランループのすべてのサイクルで排出されるでしょう。したがって、で作成されたオートリリースオブジェクト viewDidLoad メインランループに戻ると、速やかに排出される可能性があります。それらは確かに「アプリケーションの終了まで」保持されません。

しかし、注意する必要があります。これらのオブジェクトがオートレリーズプールに追加されているとはっきりと仮定しています。この仮定に対するいくつかの警告:

  1. 過去に(ARC-MRC相互運用性に必要な場合)、名前が始まっていない方法からオブジェクトを返すときに alloc, new, copy, 、 また mutableCopy, 、これらのオブジェクトはオブジェクトを自動化し、Autoreleaseプールが排出されたときにのみ取り扱います(つまり、実行ループに戻ったとき)。

  2. しかし、アークはオートレリーズプールの必要性を最小限に抑えることについて賢くなっています(参照 http://rentzsch.tumblr.com/post/75082194868/arcs-fast-autorelease, 、議論しています callerAcceptsFastAutorelease, 、今と呼ばれています callerAcceptsOptimizedReturn によって呼び出されました prepareOptimizedReturn)、したがって、あなたはしばしばこれを見ないでしょう autorelease 行動。したがって、ライブラリと発信者の両方がARCを使用している場合、オブジェクトはAutorEleaseプールに配置されない場合がありますが、ARCは不要な場合はすぐにそれらを巧みにリリースします。

    現代的なアークプロジェクトでは、一般的に自動エリーズプールは必要ありません。しかし、特定の特別なケースでは、Autoreleaseプールを使用することで恩恵を受けることができます。以下のケースの1つを概説します。

次のコードを検討してください。

#import "ViewController.h"
#import <sys/kdebug_signpost.h>

typedef enum : NSUInteger {
    InnerLoop = 1,
    MainLoop = 2
} MySignPostCodes;

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"png"];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        kdebug_signpost_start(MainLoop, 0, 0, 0, 1);
        for (int j = 0; j < 500; i++) {
            NSData *data = [NSData dataWithContentsOfURL:fileURL];
            UIImage *image = [[UIImage alloc] initWithData:data];
            NSLog(@"%p", NSStringFromCGSize(image.size));  // so it's not optimized out
            [NSThread sleepForTimeInterval:0.01];
        }
        kdebug_signpost_end(MainLoop, 0, 0, 0, 1);
    });
}

@end

次のコードでは、500,000個のオブジェクトがAutoreleaseプールに追加されます。これは、Run Loopに戻るときにのみ排出されます。

no pool

この場合、オートレリーズプールを使用して、高い水マークを最小限に抑えることができます。

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"png"];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        kdebug_signpost_start(MainLoop, 0, 0, 0, 1);
        for (int j = 0; j < 5; j++) {
            @autoreleasepool {
                kdebug_signpost_start(InnerLoop, 0, 0, 0, 2);
                for (long i = 0; i < 100; i++) {
                    NSData *data = [NSData dataWithContentsOfURL:fileURL];
                    UIImage *image = [[UIImage alloc] initWithData:data];
                    NSLog(@"%p", NSStringFromCGSize(image.size));  // so it's not optimized out
                    [NSThread sleepForTimeInterval:0.01];
                }
                kdebug_signpost_end(InnerLoop, 0, 0, 0, 2);
            }
        }
        kdebug_signpost_end(MainLoop, 0, 0, 0, 1);
    });
}

@end

pool

結論として、ARCを使用して、Autoreleaseオブジェクトを使用した場合、および変数が範囲から脱落したときに明示的に解放する場合、それは必ずしも明らかではありません。機器の動作を調べることで、いつでもこれを確認できます。

余談です。 NSString クラスは、高度に最適化されており、標準のメモリ管理の実践に常に適合するとは限らないためです。

新しいオブジェクトをオブジェクトを保持していたリファレンスに割り当てるとき、私は仮定します。 元のオブジェクトはすぐにリリースされます (他に何も指していない場合 - 参照カウントはゼロになります)ARCを使用してデフォルトを上げる strong ループの例のように参照してください。

MyObject *object = [[MyObject alloc] init]; // obj1, ref count 1 because strong
object = [[MyObject alloc] init]; // obj2, ref count of obj1 should be 0
                                  // so obj1 gets released

Apple Notes in アークリリースノートへの移行

リリースコールがどこに置かれているかについて考えるのをやめて、代わりにアプリケーションアルゴリズムについて考えてみてください。オブジェクトの「強くて弱い」ポインター、オブジェクトの所有権、および可能性のあるサイクルについて考えてください。

それはそうです release Clangから新しい値が割り当てられているときにオブジェクトで呼び出されます Clang 3.4ドキュメントObjective-Cオートマチックリファレンスカウント(ARC)

割り当てオペレーターを評価するときに割り当てが発生します。セマンティクスは、資格によって異なります。

__strongオブジェクトの場合、新しいPointeeが最初に保持されます。第二に、LValueには原始的なセマンティクスがロードされます。第三に、新しいポイントは、原始的なセマンティクスでlvalueに保存されます。そして最後に、古いポイントがリリースされます。これは原子的に実行されません。外部同期は、同時負荷とストアに直面してこれを安全にするために使用する必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top