20

ARC でコンパイルすると、メソッドの引数がメソッドの最初で保持され、最後で解放されるように見えることがよくあります。この保持/解放のペアは不必要に思え、ARC が「とにかく書いたであろうコードを生成する」という考えと矛盾します。ARC以前の暗い時代に、安全のためにすべてのメソッド引数に対して余分な保持/解放を行った人は誰もいませんでしたね?

検討:

@interface Test : NSObject
@end

@implementation Test

- (void)testARC:(NSString *)s
{
  [s length];  // no extra retain/release here.
}

- (void)testARC2:(NSString *)s
{
  // ARC inserts [s retain]
  [s length];
  [s length];
  // ARC inserts [s release]
}

- (void)testARC3:(__unsafe_unretained NSString *)s
{
  // no retain -- we used __unsafe_unretained
  [s length];
  [s length];
  // no release -- we used __unsafe_unretained
}

@end

リリース モードで Xcode 4.3.2 を使用してコンパイルすると、(私が理解できるように) アセンブリには、2 番目のメソッドの最初と最後に呼び出しが含まれていobjc_retainましobjc_releaseた。どうしたの?

これは大きな問題ではありませんが、Instruments を使用してパフォーマンスが重要なコードをプロファイリングすると、この余分な保持/解放トラフィックが発生します。3 番目の例で行ったように、この余分な保持/解放を避けるためにメソッドの引数を で装飾できるようですが__unsafe_unretained、そうすると非常にうんざりします。

4

4 に答える 4

21

Objc-language メーリング リストからのこの返信を参照してください。

コンパイラが関数またはメソッドのメモリ管理動作について何も知らない場合 (そしてこれが頻繁に発生します)、コンパイラは次のことを想定する必要があります。

1) 関数またはメソッドが、アプリケーションのオブジェクト グラフ全体を完全に再配置または置換する可能性があること (おそらくそうはなりませんが、可能性はあります)。2) 呼び出し元が手動参照カウント コードである可能性があるため、渡されたパラメーターの有効期間は現実的にはわかりません。

与えられた #1 と #2; また、ARCがオブジェクトの早期割り当て解除を許可してはならないことを考えると、これら 2 つの仮定により、コンパイラは渡されたオブジェクトを多くの場合保持する必要があります。

主な問題は、メソッドの本体が引数の解放につながる可能性があるため、ARCが防御的に行動してそれらを保持する必要があることだと思います:

- (void) processItems
{
    [self setItems:[NSArray arrayWithObject:[NSNumber numberWithInt:0]]];
    [self doSomethingSillyWith:[items lastObject]];
}

- (void) doSomethingSillyWith: (id) foo
{
    [self setItems:nil];
    NSLog(@"%@", foo); // if ARC did not retain foo, you could be in trouble
}

メソッド内の呼び出しが 1 回だけの場合に余分な保持が表示されないのも、これが理由である可能性があります。

于 2012-04-25T07:32:33.113 に答える
2

通常、パラメータとして渡しても保持カウントは増加しません。ただし、のようなものに渡す場合は、新しいスレッドのパラメーターを保持することNSThreadが具体的に文書化されています。

したがって、この新しいスレッドをどのように開始しようとしているかの例がなければ、明確な答えを出すことはできません. ただし、一般的には問題ないはずです。

于 2012-07-17T12:44:38.860 に答える
2

魂の答えでさえ正しいですが、本来あるべきよりも少し深いです:

渡された参照は強力な変数であるパラメーター変数に割り当てられるため、保持されます。これだけが保持/解放ペアの理由です。(パラメーター var を __weak に設定するとどうなりますか?)

それを最適化できますか?パラメータはローカル変数であるため、ローカル変数のすべての保持/解放ペアを最適化するようなものです。これは、送信されたすべてのメッセージと関数呼び出しを含むメソッド内のホール コードをコンパイラが理解している場合に実行できます。これは、そのclangがそれをやろうとさえしないことはめったにありません。(arg がグループに属する人 (のみ) を指し、そのグループが割り当て解除されていると想像してください。その人も割り当て解除されます。)

はい、MRC で引数を保持しないことは一種の危険でしたが、通常、開発者は自分のコードが優れていることを知っており、何も考えずに保持/解放を最適化しました。

于 2014-05-22T15:41:06.020 に答える
1

舞台裏では増加しません。ARCでは、オブジェクトが強力である場合、オブジェクトへの強力なポインターがなくなるまで、オブジェクトは単に存続します。しかし、これは実際には、オブジェクトがパラメーターとして渡されるかどうかとは関係ありません。

于 2012-07-17T12:29:16.697 に答える