9

自動解放プールが設定されていない場合のシナリオをキャッチしようとしています。
これは私のテストアプリです。

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [self performSelectorInBackground:@selector(bgOperation:) withObject:nil];
}

- (void)bgOperation:(id)obj
{
    NSString *string [[[NSString alloc] init] autorelease];
}

ブレークポイントobjc_autoreleaseNoPoolを設定してみました。
Instruments/Leaksでプロファイリングを試しました。
OSX 10.7.5 XCode 4.3.3ターゲティング10.6、AutomaticRefCounting = NO、GarbageCollection=サポートされていません。

NSApplicationには独自の自動リリースプールが含まれていることを理解しています。しかし、私の理解では、performSelectorInBackground:を呼び出すたびに、独自の自動解放プールが必要でした。

提案からの更新:
私はこれを試しまし
た..main.mで、運がありません。

int main(int argc, char *argv[])
{
    NSString *junk = [[[NSString alloc]init]autorelease];
    return NSApplicationMain(argc, (const char **)argv);
}

そしてこれ..
私のappDelegateでも、結果はありません。

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [NSThread detachNewThreadSelector:@selector(bgOperation:)
                             toTarget:self
                           withObject:nil];
}

そしてこれ..
私のmain.mにpthreadを使用

void *doJunk(void *ptr){
  NSString *junk = [[[NSString alloc]initWithString:@"string with no pool"]autorelease];
  NSLog(@"%@", junk);
  pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
  pthread_t thread;
  pthread_create(&thread, NULL, doJunk, NULL);
  return NSApplicationMain(argc, (const char **)argv);
}

OSレベルが原因で、リークが発生していない可能性があることは理解しています(まだ確認されていません)が、10.6をターゲットにすると、ログに「プールなし」というメッセージが多数表示されます。OSレベルが原因でリークするだけの場合は、10.6をターゲットにしているが10.7 SDKを使用しているときに、10.7でこれらのシナリオをキャッチする方法が必要です。

4

2 に答える 2

5

performSelectorInBackground:最近は自動解放プールを自動的に設定するdispatch_queueを使用している可能性があります。新しい NSThread を直接起動してみて、リークが発生するかどうかを確認してください。

同じ動作をする NSApplicationMain の前にコードを移動することもできます。

于 2012-12-19T17:50:59.117 に答える
1

ドキュメントによると、この状況でプールを作成することは依然として必須です。

PerformSelectorInBackground :withObject:メソッドは、新しいデタッチスレッドを作成し、指定されたメソッドを新しいスレッドのエントリポイントとして使用します。

[...]

このメソッドを呼び出す効果は、現在のオブジェクト、セレクター、およびパラメーターオブジェクトをパラメーターとしてNSThreadのdetachNewThreadSelector:toTarget:withObject:メソッドを呼び出した場合と同じです。新しいスレッドは、デフォルト構成を使用してすぐに生成され、実行を開始します。セレクター内では、他のスレッドと同じようにスレッドを構成する必要があります。たとえば、自動解放プールを設定し(ガベージコレクションを使用していない場合)、使用する予定がある場合はスレッドの実行ループを構成する必要があります。

次に、のドキュメントによるNSThread

+ (void)detachNewThreadSelector:(SEL)aSelector
                       toTarget:(id)aTarget
                     withObject:(id)anArgument

ガベージコレクションされていないアプリケーションの場合、メソッドaSelectorは、新しくデタッチされたスレッドの自動解放プールを設定し、終了する前にそのプールを解放します。

したがって、Appleが実装を文書化せずに変更しない限り(ほとんどありません)、を使用する別のスレッドで実行されるセレクターには、プールの作成が必須autoreleaseです。

ドキュメントが真実を述べているかどうかを確認するために、あなたの呼び出しを置き換えてみてください

[self performSelectorInBackground:@selector(bgOperation:) withObject:nil];

[NSThread detachNewThreadSelector:@selector(bgOperation:) toTarget:self withObject:nil];

ドキュメントによると、上記の2つの呼び出しは同等である必要があります。あなたは彼らがそうではないことに気付くかもしれません。

于 2012-12-30T14:56:02.217 に答える