0

http://i46.tinypic.com/2nquzag.png

非常に長い計算の過程で数百万のNSNumberを作成してリリースするアプリがあります。これらのオブジェクトを作成および処理するさまざまなループで@autoreleasepoolsを使用しています。機器の画面の上限からわかるように、生きているCFNumberは10656個しかありませんが、この時点で、他のオブジェクトにメモリを割り当てることができないため、アプリがクラッシュします。「一時的な」状態のCFNumberは5700万を超えています。これは彼らが解放されることを意味しますか?なぜmallocはこれらのメモリ位置をまだ使用しないのですか?

使用しているコードのモックアップを含めました。testProbabilitiesメソッドを実行すると、10000回の反復ごとにカウントされます。割り当てエラーが発生する前に、このコードで最大790000回の反復が発生しています。それでも、Instrumentsは私には良さそうです。

@implementation MMTest

NSMutableSet *predictedSet;


-(NSMutableArray *)calculateCDF {

//// NORMALIZE PROBABILITIES ////

float probabilitySum = 0;
float runningCDFTotal = 0;
float normaledProbability = 0;

@autoreleasepool {

    NSMutableArray *CDF = [[NSMutableArray alloc] init];

    probabilitySum = 4.5; ////This is just a placholder for additive iteration of an array which creates this sum.

    //// CREATE CDF ////

    int x;

    for (x=0; x<50; x++) {

        normaledProbability = .2/probabilitySum;////This is placeholder for calculation on same array as above.
        runningCDFTotal += normaledProbability;

        [CDF addObject:[NSNumber numberWithFloat:runningCDFTotal]];

    }

    return CDF;

}

}

-(NSMutableSet *)generateNumbers {

@autoreleasepool {

    int x;
    double r = 0;

    if (!predictedSet) {
        predictedSet = [[NSMutableSet alloc] init];
    }

    else {
        [predictedSet removeAllObjects];
    }

    for (x=0; x<5;) {

        r = arc4random_uniform(1000)/1000;////I'm actually using SFMT here instead.
        int num = 0;
        __weak id CDF = [self calculateCDF];


        if (r <= [[CDF objectAtIndex:[CDF count]-1] floatValue]) {

            for (NSNumber *cdf in CDF) {

                if (r <= [cdf floatValue]) {

                    num = [CDF indexOfObject:cdf]+1;

                    [predictedSet addObject:[NSNumber numberWithInt:num]];

                    x++;

                    break;


                }

            }

        }

    }

    return predictedSet;

}

}

-(void)testProbability {

int x = 0;
BOOL nextSetFound = NO;
NSSet *nextSet = [[NSSet alloc] initWithObjects:
                  [NSNumber numberWithInt:1],
                  [NSNumber numberWithInt:2],
                  [NSNumber numberWithInt:3],
                  [NSNumber numberWithInt:4],
                  [NSNumber numberWithInt:5],
                  nil];

while (nextSetFound == NO) {

    @autoreleasepool {

        __weak id newSet = [self generateNumbers];

        x++;

        if ([nextSet isSubsetOfSet:newSet]) {

            nextSetFound = YES;
            NSLog(@"%@", newSet);

        }   

        if (fmod (x,10000) == 0) {
            NSLog(@"%i", x);

        }

    }

}

NSLog(@"%i", x);

}

@end
4

2 に答える 2

1

私は間違っていますか、それともどこにもリリースしていませんCDFか?CDFこのように、あなたはあなたが呼ぶたびに漏れていますcalculateCDF

これを試して:

id CDF = [self calculateCDF];

それ以外の

 __weak id CDF = [self calculateCDF];

id newSet = [self generateNumbers];

それ以外の

__weak id newSet = [self generateNumbers];

指定weakすると、オブジェクトはARCによって所有されないため、newSetARCによって自動的に解放されなくなります。

一方、Appleは、スタック変数の使用に明示的に反対して__weakいます。

スタックで__weak変数を使用する場合は注意してください。次の例を考えてみましょう。

       NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
       NSLog(@"string: %@", string);

文字列は最初の割り当ての後に使用されますが、割り当て時に文字列オブジェクトへの強い参照は他にありません。したがって、すぐに割り当てが解除されます。logステートメントは、文字列にnull値があることを示しています。(たとえば、を使用した場合、効果は表示されませんNSString * __weak string = [[NSString alloc] initWithString:@"First Name"]。この場合、initWithString:割り当てが解除されることのない文字列定数を返すだけです。)

この段落を理解しているように、すぐに割り当てが解除されるか、メモリリークが発生します。

iOS 4.3 iPhoneでコードを試してみました(__weakを削除)。楽器の下にフラットな「物理的な空きメモリ」が表示されます。

古い答え:

トリッキーなことautoreleaseは、自動解放プールが予測できない時間(通常はアプリが実行ループを実行するとき)に排出されることです。これはrelease、オブジェクトの処理が完了した瞬間とメモリが解放される瞬間の間に遅延が追加されるという点で、使用とは異なります。

この小さな遅延(autoreleaseシステムの慣性など)に自動解放されたオブジェクトの数を掛けると、メモリ使用量のピークにつながる可能性があります。iOSがこれらのピークの1つでメモリ使用量をチェックし、その後のメモリ警告にアプリが適切に反応できない場合、アプリは強制終了されます。

一方、リリースプールを割り当て、実行サイクルの同じステップ内でそれが巨大になると、これも過剰なメモリ使用量につながる可能性があります。

あなたはあなたのコードについてほとんど詳細を提供していないので、私はこれ以上正確にすることはできません。いずれにせよ、release可能であれば、オブジェクトを明示的にしようとします。これにより、上記の2つの問題が解消されます。または、より小さな自動解放プールを試して処理することもできます(そして、第2種の問題を修正します)...

また、Instrumentsにメモリモニターを追加して、システムがメモリを解放する速度を確認することをお勧めします。

PS:さて、あなたが添付した写真で私を驚かせたのは、割り当て図が完全にフラットであるということです。割り当ても割り当て解除もありません。私はメモリが上下することを期待します(これは私の経験では、健全なiOSアプリの兆候です)。

于 2012-07-01T06:59:36.670 に答える
0

正確な理由はわかりませんが、上記の正確なコードはそのまま正常に機能しています。さまざまな変更をテストする過程で、XcodeでGuardMallocとMallocStackLoggingを有効または無効にしました。突然、変更したバージョンがクラッシュすることなく実行を開始しました。その後、この元のバージョンをもう一度試しましたが、クラッシュすることなく正常に動作します。それは意味がありませんが、私はそれが機能していることを嬉しく思います。

@sergio:少なくともこのコードをさらに最適化するための多くのヘルプとアドバイスを提供するためにあなたの答えに賛成したいと思いますが、私は十分に高い評判を持っていません。ご協力ありがとうございました。ありがたいです。

于 2012-07-07T11:49:20.050 に答える