1

ARC(自動参照カウント)を使用して、奇妙で(私には見える)単純なメモリリークの状況があります。私は iOS コードで作業していますが、Objective-C 全般に適用する必要があると思います。


パラメータオブジェクトのプロパティをチェックした後、パラメータとして割り当てられたオブジェクトを返す次の関数があります。

- (id) returnParam:(id) obj
{
    // Do whatever filtering needed. Return nil for invalid input.

    return (NSNumber *)obj;
}

このメソッドを次のようにループで呼び出すと、Instruments でループが終了するまで、割り当てられたメモリが増加し続けることがわかります。

for(int i = 0; i < 1000000; i++)
{        
    id obj = [[NSNumber alloc] initWithInt:i];        
    id obj2 = [self returnParam:obj];
    NSLog(@"attempt %@", obj2);
}


しかし、returnParam次のように関数の内容をループに入れると、すべて正常に動作します。メモリーフットスタンプはずっと同じサイズのままです。

for(int i = 0; i < 1000000; i++)
{        
    id obj = [[NSNumber alloc] initWithInt:i];

    // Do whatever filtering needed. Break on invalid input.

    id obj2 = obj;

    NSLog(@"attempt %@", obj2);
}


フィルタリングの部分を削除したため (基本的に、関数はオブジェクトを呼び出し元に戻すだけです)、同じ状況が続きます。


このシーケンスが保持カウントを想定どおりに減少させない理由を理解できず、可能なすべての組み合わせを__weak__unsafe_unretainedあちこちで試しましたが、どれも機能しませんでした。

なぜこれ(パラメーターオブジェクトを返す)が機能しないのかを説明し、この問題の解決策を提案してもらえますか?


PS ところで、Instruments ではメモリ リーク イベントとしてキャプチャされませんが、私が考える状況は明らかなメモリ リークです。

4

1 に答える 1

3

漏れではありません。それはどのように機能するかと関係があります-autorelease。何をするかを拡張する-returnParam:

-(id) returnParam:(id) paramToReturn
{
   // make sure the variable is in the scope for the entirety of the function
   id returnValue = nil;
   @try 
   {
       // when the parameter is passed in, ARC will automatically retain it.
       [paramToReturn retain];
       returnValue = [paramToReturn retain]; // strong assignment (a = b)
       return returnValue;
   }
   @finally
   {
       [paramToReturn release]; // release the value we retained when we passed in the parameter
       [returnValue autorelease]; // autorelease the return value so it is still valid after the function exits.
   }
}

それでは、これを他のループと比較してみましょう。

for (int i = 0; i < 1000; i++)
{
    id obj = [[NSNumber numberWithInt:i] retain]; // retain, because 'obj' is strong by default.
    id obj2 = [obj retain]; // retain, because 'obj2' is strong by default

    NSLog(@"attempt %@", obj2);

    [obj release]; // release because 'obj' is strong
    [obj2 release]; // release because 'obj2' is strong.
}

したがって、変数は次の自動リリースプールがポップされるまでクリーンアップされません。これは通常NSRunLoop、iPhoneアプリの次のティックで、または@autoreleasepoolコンソールアプリケーションの最後で発生します。

于 2012-05-26T15:47:18.637 に答える