10

次のコードは最大 410MB のメモリを占有し、再度解放しません。dispatch_sync(代わりに を使用するバージョンでdispatch_asyncは、最大 8MB のメモリが必要です)
メモリ使用量が急増することが予想されますが、再び低下するはずです... リークはどこにありますか?

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    for (int i = 0; i < 100000; i++) {
      dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
        NSLog(@"test");
      });
    }
    NSLog(@"Waiting.");
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60]];
  }
  return 0;
}  

私は試した:

  • ループの前後に @autoreleasepool を追加する
  • NSRunLoop runループへの追加

いくつかの組み合わせを試しましたが、メモリの減少は見られませんでした (数分待っても)。次のステートメントを含む GCD リファレンス ガイドを認識しています。

GCD ディスパッチ キューには独自の自動解放プールがありますが、これらのプールがいつ空になるかは保証されません。

このコードにメモリ リークはありますか? そうでない場合、完成したブロックを解放/排出するようにキューを強制する方法はありますか?

4

2 に答える 2

1

Objective-C ブロックは C 構造です。ブロック オブジェクトを 100000 個作成してバックグラウンド スレッドで実行し、システムが実行できるまで待機すると思います。デバイスが実行できるスレッドの数は限られています。つまり、OS が開始する前に多くのブロックが待機することになります。

「async」を「sync」に変更すると、前のブロックが終了して破棄された後に、次のブロック オブジェクトが作成されます。

UPD

GCDプールについて。

GCD は GCD スレッド プールでタスクを実行し、スレッドはシステムによって作成され、システムによって管理されます。システムはスレッドをキャッシュして CPU 時間を節約し、すべてのディスパッチ タスクは空きスレッドで実行されます。

ドキュメントから:

——</p>

ディスパッチ キューに送信されたブロックは、システムによって完全に管理されるスレッドのプールで実行されます。タスクが実行されるスレッドに関しては保証されません。

——</p>

タスクを同期タスクとして実行する場合、現在のタスクが終了した後、次のタスクを実行するための空きスレッド (GCD スレッド プールから) が存在します (タスクの実行中にメイン スレッドが待機し、新しいタスクをキューに追加しないため)。システムは新しいNSThreadを割り当てません(私のMacでは2つのスレッドを見ました)。タスクを非同期で実行すると、グローバル キューに多くのタスクが含まれるため、システムは多くの NSThreads を割り当てることができます (最大のパフォーマンスを達成するために、私の Mac では 67 スレッド近くです)。

ここでは、GCD スレッド プールの最大数について読むことができます。

Alocations プロファイラーで、多くの NSThreads が割り当てられ、破棄されていないことを見てきました。必要に応じて解放されるのはシステムプールだと思います。

于 2015-02-16T09:16:28.553 に答える
1

すべての GCD 呼び出し内に常に @autoreleasepool を入れておけば、問題はありません。私は同じ問題を抱えていましたが、これが唯一の回避策です。

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    for (int i = 0; i < 100000; i++) {
      dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
        // everything INSIDE in an @autoreleasepool
        @autoreleasepool {
          NSLog(@"test");
        }
      });
    }
    NSLog(@"Waiting.");
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60]];
  }
  return 0;
}  
于 2016-10-01T12:12:44.947 に答える