[NSKeyedUnarchiver decodeObjectForKey]によるメモリリーク
-
05-07-2019 - |
質問
このメソッドを呼び出すたびに、NSMutableDataがリークし、プラグインする方法がわかりません。 theDataの保持カウントは、デコーダーが割り当てられて初期化された後、1増加しますが、その理由はわかりません。メソッドの最後に保持カウント2で止まっており、それを解放しようとするとアプリがクラッシュします。
- (void)readVenueArchiveFile:(NSString *)inFile key:(NSString *)inKey
{
NSMutableData *theData;
NSKeyedUnarchiver *decoder;
theData = [NSData dataWithContentsOfFile:inFile];
decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
venueIOList = [[decoder decodeObjectForKey:inKey] mutableCopy];
[decoder finishDecoding];
[decoder release];
}
解決
この行を置き換えることをお勧めします:
venueIOList = [[decoder decodeObjectForKey:inKey] mutableCopy];
with:
ListClassName *decodedList = [decoder decodeObjectForKey:inKey];
self.venueIOList = decodedList;
これにより、 decodedList
のメモリ管理が明確になります。アクセサメソッドを使用してインスタンス変数を割り当てることをお勧めします(initメソッドを除く)。現在の実装では、同じオブジェクトで readVenueArchiveFile:
を2回呼び出すと、( decodedList
が既にある場合と同様に) decodeList がリークします。値があります)。さらに、新しい値を割り当てるたびにmutableCopyを覚える必要はなく、アクセサーメソッドにコピーロジックを入れて、それを忘れることができます(とにかく変更可能なコピーを作成する正当な理由があると仮定します)。
他のヒント
ピークメモリフットプリントの削減
一般に、自動リリースされたオブジェクトの生成を避けることがベストプラクティスと見なされます。
[この段落の大部分はこの質問から修正されました。]通常、(1)存続期間を直接制御することはできません。自動解放されたオブジェクトは比較的長時間持続し、アプリケーションのメモリフットプリントを不必要に増加させる可能性があります。デスクトップではこれはほとんど問題になりませんが 、制約の厳しいプラットフォームではこれは重大な問題になります。したがって、すべてのプラットフォームで、特に制約の厳しいプラットフォームでは、可能であれば、自動リリースされたオブジェクトにつながるメソッドを使用することは強く推奨されず、代わりにalloc / initパターンの使用が推奨されます。
これを置き換えることをお勧めします:
theData = [NSData dataWithContentsOfFile:inFile];
with:
theData = [[NSData alloc] initWithContentsOfFile:inFile];
メソッドの最後に追加:
[theData release];
これは、メソッドが終了する前に theData
の割り当てが解除されることを意味します。
最終的には次のようになります。
- (void)readVenueArchiveFile:(NSString *)inFile key:(NSString *)inKey
{
NSMutableData *theData;
NSKeyedUnarchiver *decoder;
theData = [[NSData alloc] initWithContentsOfFile:inFile];
decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
ListClassName *decodedList = [decoder decodeObjectForKey:inKey];
self.venueIOList = decodedList;
[decoder finishDecoding];
[decoder release];
[theData release];
}
これにより、メモリ管理のセマンティクスが明確になり、可能な限り迅速にメモリが解放されます。
(1)独自のローカル自動解放プールを使用して制御できます。詳しくは、 Appleのメモリ管理プログラミングガイド。
カウントの保持について心配する必要はありません。メソッド内のバランスについて心配します。 venueIOList
がインスタンス変数であると仮定すると、このメソッドで行っていることは正しいように見えます。
私の答えを少し拡大するには:アーカイブ解除操作中にアーカイブ解除プログラムがデータを保持し、 -release の代わりにデータ
-autorelease
を送信している可能性がありますコード>。それはあなたがしたことではないので、あなたが気にしなければならないものではありません。
refcount関連のメモリ管理啓発の究極のソースは、IMOです。"ホールドミー、ユースミー、フリーミー" Stepwiseから。
コードは正しいです。メモリリークはありません。
theData = [NSData dataWithContentsOfFile:inFile];
は
と同等ですtheData = [[[NSData alloc] initWithContentsOfFile:inFile] autorelease];
この時点で、theDataの参照カウントは1です(それより少ない場合、割り当て解除されます)。参照カウントは、自動解放プールによって将来のある時点で自動的に減らされます。
decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
デコーダオブジェクトは、参照カウントを2に増やすtheDataへの参照を保持します。
メソッドが戻った後、自動解放プールはこの値を1に減らします。このメソッドの最後でtheDataを解放すると、参照カウントが0になり、オブジェクトの割り当てが解除され、アプリケーションのクラッシュが発生します使用します。