9

NSStringで奇妙な動作を見つけました。以下のコードを実行しようとしましたが、これに気づきました。

NSString *str = [[NSString alloc] initwithstring : @"hello"];
[str release];
NSLog(@" Print the value : %@", str);

ここでは、リリースされたオブジェクトにアクセスしているため、3行目でアプリがクラッシュするはずです。しかし、それはstrの値を出力しています。クラッシュしていません。しかし、NSArrayを使用すると、異なる動作が観察されました。

NSArray *array = [[NSArray alloc] initwithobjects : @"1",  @"2", nil];
[array release];
NSLog(@"Print : %@", [array objectatindex : 0]);
NSLog(@"Print : %@", [array objectatindex : 0]);

コードには、NSArrayに使用される2つのNSLogステートメントがあります。ここでは、最初のNSLogが実行されたときに解放した後、値を出力しています。しかし、2番目のNSLogが実行されると、アプリがクラッシュします。アクセスされたアレイはすでに解放されているため、アプリのクラッシュは許容されます。ただし、最初のNSLogが実行されるとクラッシュするはずです。2番目ではありません。

この振る舞いを手伝ってください。これらの場合のリリースの仕組み。

ありがとうJithen

4

5 に答える 5

7

文字列リテラルは解放されないため、最初の例はクラッシュしません。コードは実際には次のとおりです。

NSString *str = @"hello";
[str release];

人々は、メモリ管理で文字列リテラルを使用==し、代わりにそれらを誤って比較することに悩まされていますisEqualToString:。コンパイラは、誤解を招く結果につながるいくつかの最適化を行います。

更新

次のコードは私の主張を証明しています:

    NSString *literal = @"foo";
    NSString *second = [NSString stringWithString:literal];
    NSString *third = [NSString stringWithString:@"foo"]; // <-- this gives a compiler warning for being redundant
    NSLog(@"literal = %p", literal);
    NSLog(@"second = %p", second);
    NSLog(@"third = %p", third);

このコードは、次の出力を提供します。

2013-02-28 22:03:35.663 SelCast[85617:11303] リテラル = 0x359c
2013-02-28 22:03:35.666 SelCast[85617:11303] 秒 = 0x359c
2013-02-28 22:03:35.668 SelCast 85617:11303] 3 番目 = 0x359c

3 つの変数すべてが同じメモリを指していることに注意してください。

于 2013-03-01T04:51:47.397 に答える
6

NSLog最初のログではメモリが再利用されていないため、2 番目の例は 2 番目にクラッシュしますarrayが、最初のログではヒープ上で十分なアクティビティが発生し、メモリが他の何かによって使用されるようになります。その後、再度アクセスしようとするとクラッシュします。

オブジェクトの割り当てが解除され、そのメモリが空きとしてマークされるたびに、そのメモリにそのオブジェクトの残りが格納されている期間が発生します。この間、クラッシュすることなく、そのようなオブジェクトなどのメソッドを呼び出すことができます。この時間は非常に短く、多くのスレッドを実行している場合は、メソッド呼び出しを取得するのに十分ではない場合もあります。したがって、明らかに、動作についてこの実装の詳細に依存しないでください。

他の人が言ったように、最初の質問に関して、NSStringリテラルは割り当て解除されません。これは、他のいくつかの Foundation クラスにも当てはまりますが (NSNumber思い浮かびます)、実装の詳細でもあります。メモリ管理の実験を行う必要がある場合はNSObject、異常な動作を示さないため、代わりにインスタンスを使用してください。

于 2013-03-01T05:05:59.917 に答える
4

オブジェクトでメッセージを送信するときrelease、オブジェクトは実際にはメモリから削除されていません。リリースメッセージは、参照カウントを1つだけ減らすだけです。参照カウントがゼロの場合、オブジェクトは空きとしてマークされます。次に、システムはそれをメモリから削除します。この割り当て解除が発生するまで、オブジェクトにアクセスできます。オブジェクトを使用している場合でも、ポインタに割り当てていない限り、releaseオブジェクトポインタはオブジェクトnilを指します。

于 2013-03-01T04:51:29.750 に答える
0

releaseオブジェクトをすぐに破棄する必要があると想定しているようです。それは言語が保証するものではないと思います。releaseつまり、私はこのオブジェクトの使用を終了し、二度と使用しないことを約束します. その時点から、実際にいつメモリの割り当てを解除するかを決定するのはシステム次第です。

それ以降の動作は定義されておらず、Objective C ランタイムのバージョンごとに変更される可能性があります。

つまり、文字列リテラルとメモリの再利用の違いを示唆する他の回答は現在正しいですが、動作が常にこのようになると仮定するのは間違いである可能性があります。

于 2013-03-01T09:40:17.010 に答える
0

文字列リテラルは解放されないため、最初の例はクラッシュしません。2番目は完全にリリースと保持カウンターに依存します。

この記事を読んでください。クエリの簡潔でわかりやすい説明が含まれています

あなたはこのリンゴのガイドラインを読むべきです

于 2013-03-01T04:56:44.980 に答える