5

NSData オブジェクトでラップしたい大規模な malloc 領域があります。しばらくして、その NSData オブジェクトのコピーを作成します。2 つの NSData オブジェクトが独立した存続期間を持つようにしたいと考えています。ARC は NSData オブジェクト自体の参照カウントを処理しますが、含まれている malloc された regionの有効期間を明確にしようとしています。コード スケッチを次に示します。

float* cubeData = (float*)malloc(cubeDataSize);
printf("cubeData=%p\n", cubeData);
// cubeData=0x01beef00

for (...) { /* fill the cubeData array */ }

NSData* data = [NSData dataWithBytesNoCopy:cubeData length:cubeDataSize
  freeWhenDone:YES];

NSData* data2 = [data copyWithZone:nil]

printf("data.bytes=%p data2.bytes=%p\n", data.bytes, data2.bytes);
// data.bytes=0x01beef00 data2.bytes=0x01beef00

copyWithZone が malloc された領域をディープ コピーしないことは問題ありません —[NSData dataWithData:]ディープ コピーが必要な場合に使用できます。私には明確ではない (そして、テストする最善の方法がわからない) のは、どの NSData オブジェクトが基礎となる malloc されたバッファーを所有しているのか? それらが両方とも malloc されたバッファーへの参照を保持している場合 (何らかの形式の不透明な参照カウントを使用)、それは素晴らしいことです! しかし、オブジェクトが解放されたときに malloc されたバッファーが解放された場合data( によって暗示されているようにfreeWhenDone:YES)、data2問題が発生します。

この場合、NSDataが何をするのか誰か説明できますか? あるいは、誰かが何が起こっているのかを自分自身に証明するための決定的なテストを提案できますか?

4

1 に答える 1

1

根底にある質問に:

NSData のコンテンツは個別に参照カウントされますか?

いいえ。

--- 迂回開始 ---

ARC は、 と に相当するretainメッセージreleaseを適切なタイミングで送信することにより、Objective-C オブジェクトの保持と解放を管理します。「適切な時間」は、コード検査によってコンパイル時に決定されます。それがまさにそれがするすべてです。これらのオブジェクトの非オブジェクト部分 (つまりbytes) へのポインターの作成を開始すると、ライフタイムを自分で管理する必要があります。

@CouchDeveloper は、 に関する優れた情報を提供しますobjc_precise_lifetime。この属性をデータ オブジェクトに配置すると、内部ポインターを処理するときに ARC の最適化から保護できますが、ここではあまり関係ありません。ポイントはobjc_precise_lifetime、参照変数が範囲外になる前にオブジェクトを解放することは許可されていないことを ARC に伝えることです。それが解決する問題は次のようになります。

NSData *data = ...;
void *stuff = data.bytes; // (1)
doSomething(stuff); // (2)

ARC には、スコープ内であっても再度参照することはないため、行 (1) と行 (2) の間で破棄できるという最適化があります。属性を追加すると、その最適化が禁止されます。たくさん使い始めると、この属性が重要になることがあります。datadatadataobjc_precise_lifetimeNSData

--- 迂回終了 ---

わかりましたが、あなたの状況はどうですか?

float* cubeData = (float*)malloc(cubeDataSize);
NSData* data = [NSData dataWithBytesNoCopy:cubeData length:cubeDataSize freeWhenDone:YES];
NSData* data2 = [data copyWithZone:nil]

このコードが実行された後、2 つの可能性があります (これらは不変オブジェクトであるため、ほとんどの場合は気にする必要はありません)。

  • dataとはどちらも同じオブジェクトdata2への強力なポインターです。NSDataそのオブジェクトは割り当てられたメモリを所有し、割り当てが解除されると解放されます。(これは、この特定のケースでほぼ確実に発生するものですが、実装の詳細です。)
  • dataNSDatamalloc されたメモリを所有し、割り当てが解除されると解放されるオブジェクトを指します。独自のメモリをdata2持つ別のオブジェクトを指します (割り当てが解除されると解放されます)。NSData

(他のオプションがあります。おそらくNSData、基本的なdispatch_dataスキームまたはコピー オン ライト スキームを使用します。しかし、すべてのオプションは、外部からは実質的に上記のように見えるはずです。)

最初のケースでdataは、範囲外に出てdata2もまだ残っている場合、所有権NSDataは保持されます。問題ない。2 番目のケースではdata、スコープ外になるとメモリが破棄されますが、そのメモリdata2の独立したコピーがあるため、これも問題ありません。

あなたの混乱はdata、記憶を所有しているという考えから来ていると思います。そうではありません。を指すNSDataオブジェクトがメモリを所有します。単なるポインタです。datadatadata2

于 2013-07-15T21:47:16.053 に答える