4

私が取り組んでいるアプリでは、for ループでテキスト ファイルから数値を読み取り、いくつかの計算を行い、結果を結果文字列に追加しています。

ファイルには 22050 の値が含まれています。特定の数のループ/値が追加されると(〜5300)、クラッシュする傾向があることに気付きました。

おそらくメモリリークがあると思ったので、文字列の追加を取り除き、すべて正常に機能しました。文字列の追加とアプリがクラッシュした以外はすべて削除しようとしました。すべての例外にブレークポイントがあり、例外は発生しません。

確かめたかったので、新しいプロジェクトを始めました。私が入れたのは、押されたときにこのコードを呼び出すUIButtonが1つだけです。

- (IBAction)TestPressed:(id)sender
{
    NSString *testString = @"";

    for (int i = 0; i < 22050; i++)
    {
        testString = [testString stringByAppendingString:@"12.34567890\n"];
    }

    NSLog(@"%@", testString);
}

NSLog 行にブレーク ポイントがあります。前にアプリがクラッシュしました。

NSString の長さに制限はありますか? メモリを使いすぎていませんか?

4

3 に答える 3

13

問題は、反復ごとに新しい文字列を作成していることです。これを修正するには 2 つのオプションがあります: 変更可能な文字列を使用して結果を作成する:

NSMutableString *testString = [NSMutableString string];

for (int i = 0; i < 22050; i++)
{
    [testString appendString:@"12.34567890\n"];
}

NSLog(@"%@", testString);

... または自動解放プールを使用して、ループ内のインスタンスを削除します。

NSString *testString = @"";

for (int i = 0; i < 22050; i++)
{
    @autoreleasepool {
        testString = [testString stringByAppendingString:@"12.34567890\n"];
    }
}

NSLog(@"%@", testString);

最初に問題が発生した理由とその修正方法を示すためにのみ、2 番目のバージョンを含めたことに注意してください。平均長が 120,000 文字の 22049 個の一時文字列が作成されるため、依然として非効率的です。

于 2013-03-18T10:38:00.983 に答える
2

文字列を追加するために使用NSMutableStringします。そうしないと、割り当てられるメモリが多すぎます。

于 2013-03-18T10:37:21.977 に答える
0

+[NSString stringByAppendingString:]呼び出すたびに、新しい自動解放オブジェクトを作成します。自動解放されたオブジェクトは、自動解放プールがポップするまで割り当て解除されません。これは通常、イベントループの終了時を意味します。この場合、NSMutableString他の回答が示唆するように、代わりに代わりに使用するのがおそらく最善です。ただし、可変オブジェクトを使用する代わりに多くの自動解放オブジェクトを作成する必要があるという問題が発生した場合は@autoreleasepool {}、オブジェクトを作成しているコードの周りにブロックをラップして、大量のメモリが肥大化しないようにすることができます。 、ただし、@autoreleasepoolブロックのスコープ外に貼り付けたいオブジェクトを保持するように注意する必要があります。

一般に、いくつかの理由から、自動解放されたオブジェクトの使用はできるだけ避けようとしています。

1)メソッド自体に実際に自動解放プールがない限り、オブジェクトが実際に割り当て解除されるタイミングは非決定的である可能性があります。そうしないと、自動解放プールのスコープと、呼び出し元のコードがいつプールをポップするかを知る方法がありません。

2)自動リリースは、本質的に手動リリースよりも少しリソースを消費します。オブジェクトをプールに追加し、繰り返して後でリリースする必要があります。

3)自動解放は、マルチスレッド環境では特に注意が必要です。これは、スレッド間の競合によってオブジェクトが解放されることがよくあるためです。このような状況では、再現や根本原因の特定が困難な断続的なクラッシュを伴うシナリオを簡単に作成できます。

4)自動リリースを処理する場合、クラッシュは一般に分析がはるかに困難です。オブジェクトをポップする自動解放プールであるスタックトレースがよく見られます。再現しないと、オブジェクトが何であるか、どのコードパスがオブジェクトを解放しているかなどを判断することはほとんど不可能です。

5)場合によっては、リファクタリングのような単純なものが、通常は予期しない方法で自動解放されたオブジェクトに影響を与える可能性があります。単純な反復からブロックベースの反復に変更すると、オブジェクトを保持する前にオブジェクトを解放する可能性のある自動解放プールが導入されます。

通常、自動解放されたオブジェクトの最も適切な使用法は、オンザフライで作成され、コンストラクター以外のメソッドによって返されるオブジェクトです。このように、呼び出し元のコードはオブジェクトを保持する機会がありますが、呼び出されたメソッドは所有者自体を指定することを心配する必要はありません。

それはちょっと長い間、おそらく元の質問の範囲を超えていましたが、メモリ管理における適切な決定の背後にある「理由」を知ることは重要だと思います。

于 2013-03-18T10:59:21.703 に答える