4

次の形式の ARC コードがあります。

NSMutableData* someData = [NSMutableData dataWithLength:123]; ...

CTRunGetGlyphs(run, CGRangeMake(0, 0), someData.mutableBytes); ...

const CGGlyph *glyphs = [someData mutableBytes]; ...

... からメモリを読み取るが、もう参照されglyphsていない で何もしないコードが続きます。someDataCGGlyph はオブジェクト型ではなく、符号なし整数であることに注意してください。

someData完了する前に のメモリが解放されるのではないかと心配する必要はありますかglyphs(これは実際には 内を指しているだけsomeDataです)。

このコードはすべて同じスコープ内 (つまり、単一のセレクター) でありglyphssomeData両方が同時にスコープ外になります。

PSこの質問の以前のドラフトでは、「ガベージコレクション」に言及しましたが、これは私のプロジェクトには実際には当てはまりませんでした。そのため、以下のいくつかの回答では、ARCの下で起こることと同等の扱いをしています.

4

4 に答える 4

4

GCを使用するか、他の人が代わりに推奨するようにARCを使用するかにかかわらず、問題が発生する可能性があります。あなたが扱っているのは、実装が特別な場合を除いて、一般的にGCまたはARCのいずれにおいても所有参照とは見なされない内部ポインタです。その所有参照がないと、GCまたはARCのいずれかがオブジェクトを削除する可能性があります。あなたが直面する問題は、内部ポインタに特有のものです。NSData

あなたがあなたの状況を説明するとき、最も安全なことは本当の参照に固執することです。これを行うにはNSData、インスタンス変数またはstatic(必要に応じてローカルメソッド)変数のいずれかに参照を割り当てnil、内部ポインターを使用した後でその変数に割り当てます。static並行性に注意する場合!

実際には、コードはおそらくGCとARCの両方で機能し、おそらくARCで機能する可能性が高くなりますが、特にコンパイラが変更されると、どちらかがあなたを噛む可能性があります。1つの変数宣言と1つの追加の割り当てのコストで、問題を回避できます。安価な保険です。

[ ARCでの短い寿命の例としてこの議論を参照してください。]

于 2012-09-14T20:27:27.747 に答える
3

実際の実際のガベージ コレクションでは、そのコードが問題になる可能性があります。オブジェクトへの参照がなくなるとすぐにオブジェクトが解放される可能性があり、二度と使用しない場合、コンパイラはいつでも参照を破棄する可能性があります。最適化の目的で、スコープはその種のものに上限を設定する方法であり、絶対に指示する方法ではありません。

ライフサイクル計算を C プリミティブ ポインターにアタッチするために使用できますがNSAllocateCollectable、これは面倒で少し複雑です。

ガベージ コレクションは iOS では実装されておらず、現在 Mac では廃止されています (この FAQの一番下で参照されているように)。どちらの場合も、自動参照カウント (ARC) を支持しています。ARC はretains を追加releasesし、それらが暗黙的に必要であることを確認できる場所に追加します。悲しいことに、返される結果として使用された場合に自動解放プールからオブジェクトを取得するなど、以前は不可能だった巧妙なトリックを実行できます。つまり、ガベージ コレクションのアプローチと同じ正味の効果があります。オブジェクトへの最終参照が消滅した後、オブジェクトはいつでも解放される可能性があります。

回避策は、次のようなクラスを作成することです。

@interface PFDoNothing

+ (void)doNothingWith:(id)object;

@end

これは何もしないように実装されています。内部メモリの使用が終了したら、自動解放されたオブジェクトをポストします。Objective-C の動的ディスパッチは、コンパイラが呼び出しを最適化するのは安全ではないことを意味します — コンパイラは、実行時にメソッドの入れ替えのようなことをしていないことを知る方法がありません (または KVO メカニズムやその他のアクター)。

編集:NSDataオブジェクトが保持するメモリへの直接のCレベルアクセスを提供するため、特別なケースであるため、少なくともGCの状況に関する明示的な議論を見つけることは難しくありません。上記と同じ警告が適用されますが、かなり良いスレッドについては Cocoabuilder のこのスレッドを参照してください。つまり、ガベージ コレクションは非推奨であり、自動参照カウントの動作は異なります。

于 2012-09-14T19:06:36.313 に答える
2

以下は、Objective-C GC サポートを必ずしも反映していない一般的な回答です。ただし、ref-counting を含むさまざまな GC 実装は、癖はさておき、到達可能性の観点から考えることができます。


GC 言語では、 Strongly -Reachableである限り、オブジェクトの存在が保証されます。これらの Strong-Reachability グラフの「ルート」は、言語や実行環境によって異なります。「強く」の正確な意味もさまざまですが、一般的にはエッジが強い参照であることを意味します。(手動の参照カウントのシナリオでは、各エッジは、特定の「所有者」からの比類のない「保持」と考えることができます。)

CLR/.NET 上の C# は、変数がスコープ内にとどまり、到達可能性グラフの「ルート」として機能しない、そのような実装の 1 つです。クラスを見て、次Systems.Timer.Timerを探しますGC.KeepAlive

タイマーが実行時間の長いメソッドで宣言されている場合は、KeepAlive を使用して、メソッドが終了する前に [タイマー オブジェクトで] ガベージ コレクションが発生しないようにします。

于 2012-09-14T19:03:55.633 に答える
2

2012 年の夏の時点で、非オブジェクト型の内部ポインターを返す Apple オブジェクトの変更が進行中です。Mountain Lionのリリースノートで、Apple は次のように述べています。

NS_RETURNS_INNER_POINTER

ポインターを返すメソッド (Objective C オブジェクト型以外) は、clang コンパイラー属性 objc_returns_inner_pointer (clang でコンパイルする場合) で修飾され、コンパイラーがこれらのメッセージのレシーバー式を積極的に解放するのを防ぎます。返されたポインタはまだ使用中の可能性があります。

NSData.h ヘッダー ファイルを調べると、これは iOS 6 以降にも適用されることがわかります。

また、clang仕様のようにNS_RETURNS_INNER_POINTER定義されていることに注意してください。__attribute__((objc_returns_inner_pointer))

オブジェクトの有効期間は、少なくとも次のいずれか早い方まで延長されます。呼び出し元の関数で、返されたポインターまたはそれから派生したポインターが最後に使用されたとき。または、自動解放プールが以前の状態に復元されます。

警告: Mountain Lion または iOS 6 より古いものを使用している場合でも__attribute__((objc_precise_lifetime))、ローカルの NSData または NSMutableData オブジェクトを宣言するときに、ここで説明するメソッド (例: ) を使用する必要があります。

また、最新のコンパイラと Apple ライブラリを使用しても、内部ポインターを返すメソッドを装飾しないオブジェクトで古いライブラリまたはサードパーティのライブラリを使用する場合は、__attribute__((objc_returns_inner_pointer))そのようなオブジェクトのローカル変数宣言を装飾するか、次__attribute__((objc_precise_lifetime))のいずれかを使用する必要があります。回答で説明されている他の方法。

于 2012-09-21T03:44:34.920 に答える