iOSは、パフォーマンスの最適化、メモリ漏洩の問題の解決に関するものを開発しています.

7243 ワード

メモリ漏洩の問題の解決
メモリリーク(Memory Leaks)は、オブジェクトまたは変数が使用完了後に解放されない場合、アプリケーションが停止するまでこのメモリを保持します.このオブジェクトが多すぎるとメモリが消費され、他のアプリケーションは実行できません.この問題はC+,CおよびObjective−CのMRRにおいて比較的一般的な問題である.
Objective-Cでオブジェクトを解放するメモリはreleaseメッセージとautoreleaseメッセージを送信します.これらはすべて参照カウントを1に減らすことができます.参照カウントが0の場合、releaseメッセージはオブジェクトをすぐに解放し、autoreleaseメッセージはオブジェクトをメモリ解放プールに入れて解放を遅らせます.
上のコード:
- (void)viewDidLoad

{

[super viewDidLoad];

NSBundle *bundle = [NSBundle mainBundle];

NSString *plistPath = [bundle pathForResource:@"team"

ofType:@"plist"];

//              

self.listTeams = [[NSArray alloc] initWithContentsOfFile:plistPath];

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

static NSString *CellIdentifier = @”CellIdentifier”;

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

}

NSUInteger row = [indexPath row];

NSDictionary *rowDict = [self.listTeams objectAtIndex:row];

cell.textLabel.text =  [rowDict objectForKey:@"name"];

NSString *imagePath = [rowDict objectForKey:@"image"];

imagePath = [imagePath stringByAppendingString:@".png"];

cell.imageView.image = [UIImage imageNamed:imagePath];

cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

return cell;

}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

NSUInteger row = [indexPath row];

NSDictionary *rowDict = [self.listTeams objectAtIndex:row];

NSString *rowValue  =  [rowDict objectForKey:@"name"];

NSString *message = [[NSString alloc] initWithFormat:@”    %@ 。”, rowValue];

UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@”     ”

message:message

delegate:self

cancelButtonTitle:@”Ok”

otherButtonTitles:nil];

[alert show];

[tableView deselectRowAtIndexPath:indexPath animated:YES];

}

上の3つの方法を見てみましょう.どんな問題がありますか.コードがARCベースであれば問題ありませんが、残念ながらMRRベースで、上記のコードはメモリ漏れの可能性があります.理論的には、メモリの漏洩はオブジェクトまたは変数が解放されていないことに起因しますが、すべての未解放オブジェクトまたは変数がメモリの漏洩を引き起こすわけではありません.これはハードウェア環境とオペレーティングシステム環境に関係しています.そのため、検出ツールがこれらの「漏洩点」を見つけるのに役立ちます.
Xcodeには2つのツールが用意されています.AnalyzeとProfileです.Analyzeは静的解析ツールで、メニューProduct→Analyzeで起動し、静的解析後のコード画面です.Profileはダイナミック分析ツールで、このツールは「Instruments」と呼ばれ、Xcodeが統合されており、XcodeでメニューProduct→Profileで起動することができ、Instrumentsには多くのTrace Template(トレーステンプレート)がメモリ、CPU、ファイルシステムをダイナミックに分析し、追跡することができます.
2つのツールを組み合わせて漏れ点を検索し、Analyze静的解析を使用して不審な漏れ点を検索し、Profile動的解析のLeaksとAllocationsトラッキングテンプレートを使用して動的追跡分析を行い、これらの点が漏れているかどうか、または新しい漏れが発生しているかどうかを確認することができます.
線分はプログラム実行のパスを示しており、このパスでは、1:25行のObjective-Cオブジェクト参照カウントが1であることを示し、ここでObjective-Cオブジェクトが作成されたことを示している.2:27行で参照カウントが1であることを説明し、このオブジェクトは解放されず、漏洩の疑いがある.このような説明は、問題点を明確に示しています.[[NSArray alloc]initWithContentsOfFile:plistPath]は、オブジェクトを作成し、listTeamsプロパティによって表されるメンバー変数に値を割り当てますが、値の割り当てが完了すると、作成されたオブジェクトはreleaseメッセージとautoreleaseメッセージを明示的に送信しません.コード修正
NSArray *array = [[NSArray alloc] initWithContentsOfFile:plistPath];

self.listTeams = array;

[array release];

tableView:cellForRowAtIndexPath:メソッドの疑似漏洩点行の末尾にある青いアイコン展開解析結果を見てみましょう
ここでは主に、UItableViewCell*タイプのcellオブジェクトが64行で漏洩する可能性があることを示しています.テーブルビューでtableView:cellForRowAtIndexPath:テーブルビューのセルをインスタンス化してデータを設定する方法です.そのため、cellオブジェクトをインスタンス化した後、すぐにreleaseをreleaseすることはできません.autoreleaseを使用してリリースを遅延する必要があります.cellオブジェクトを作成するときにautoreleaseメッセージを送信できます.コードは次のように変更されます.
if (cell == nil) {

cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

}

tableView:didSelectRowAtIndexPath:メソッドの疑似漏れ点が2つあり、行の末尾のアイコンが解析結果を展開しています.
 
Messageオブジェクトは作成後に解放されません.[alert show]の後に[message release]文コードを追加するだけでいいです.Objective-Cでオブジェクトをインスタンス化するには、次の2つの方法があります.
NSString *message = [[NSString alloc] initWithFormat:@”    %@ 。”, rowValue];                             ①

NSString *message = [NSString stringWithFormat:@"    %@ 。", rowValue];                           ②

①行はinit-で始まり、allocの後に呼び出されるメソッドを「インスタンス構築メソッド」と呼びます.オブジェクト所有権の作成は呼び出し者であり、呼び出し者はライフサイクルに責任を負い、具体的には作成と解放を担当する必要があります.もう1つは、2行に示すstring-(NS後クラス名を除く)の先頭メソッドです.これは、作成されたオブジェクト所有権が非呼び出し者の所有であり、呼び出し者がそれを解放する権利がありません.そうしないと、遷移解放によって「ゾンビ化」されます.
UIAlertView*タイプalertオブジェクトは作成後解放されません.[alert show]の後に[alert release]文コードを追加すればいいだけです.修正後のコード
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

NSUInteger row = [indexPath row];

NSDictionary *rowDict = [self.listTeams objectAtIndex:row];

NSString *rowValue  =  [rowDict objectForKey:@"name"];

NSString *message = [[NSString alloc] initWithFormat:@”    %@ 。”, rowValue];

UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@”     ”

message:message

delegate:self

cancelButtonTitle:@”Ok”

otherButtonTitles:nil];

[alert show];

[alert release];

[message release];

[tableView deselectRowAtIndexPath:indexPath animated:YES];

}

前述のAnalyze静解析を使用して疑わしい漏れ点を検索することを「疑わしい漏れ点」と呼ぶが、これらの点が必ずしも漏れているとは限らず、これらの点が漏れているかどうかを確認するにはProfile動的解析ツールInstrumentsのLeaksとAllocations追跡テンプレートを通過しなければならない.Analyze静解析は理論的な予測過程にすぎない.メニューProduct→Profileで起動し、Profile動的解析ツールでLeaksテンプレートを選択
InstrumentsではLeaksテンプレートが選択されていますが、デフォルトではAllocationsテンプレートも追加されています.基本的に分析メモリではAllocationsテンプレートが使用されます.メモリの分布を監視できます.Allocationsテンプレート(図中①の領域)を選択すると、右側③の領域に時間の経過とともにメモリの折れ線グラフが表示されます.同時に、④領域にメモリ使用の詳細が表示され、オブジェクトの割り当て状況が表示されます.Leaksテンプレート(図中②領域)をクリックすると、メモリリークの状況が表示され、③領域に赤い線が表示されるとメモリリークがあり、④領域にリークの対象が表示されます.
漏洩は、テーブルビューのセルテストtableView:d i d SelectRowAtIndexPath:メソッドメソッドをクリックしたときに発生します.NSCFStringタイプのオブジェクトが漏洩し、NSCFStringタイプはNSFoundationでNSString*タイプです.漏洩オブジェクトの前の三角形をクリックしてオブジェクトを展開すると、メモリアドレス、占有バイト、属するフレームワーク、応答方法の情報が表示されます.
拡張詳細ビューを開くと、右側のトレーススタック情報が表示され、自分でコードを適用し、私たちのプログラムコードにアクセスすると、対応するコードが開きます.
コード77は、リークポイントではなく、NSString*タイプのオブジェクトがその後にリークしたため、メッセージオブジェクトがその後解放されなかったことによるリークであると断定できる.コードを変更するには、次のようにします.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

NSUInteger row = [indexPath row];

NSDictionary *rowDict = [self.listTeams objectAtIndex:row];

NSString *rowValue  =  [rowDict objectForKey:@"name"];

NSString *message = [[NSString alloc] initWithFormat:@”    %@ 。”, rowValue];

UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@”     ”

message:message

delegate:self

cancelButtonTitle:@”Ok”

otherButtonTitles:nil];

[alert show];

    [message release];

[tableView deselectRowAtIndexPath:indexPath animated:YES];

}

[message release]文を追加します.また、alertオブジェクト(UIAlertView*)から漏洩が予想されるため、Instrumentsツールを再実行し、セルテストを繰り返しクリックしたが、メモリ漏洩を示す赤い線は見つからなかった.Instrumentsツールでは、alertオブジェクトが解放されないとメモリが漏れることはないと考えられています.メモリへの応用をさらに評価したい場合は、Allocationsテンプレートの折れ線グラフを見て、クリックするたびに総消費メモリ数が増加します.これは、alertオブジェクトが解放されていないことを示しています.深刻ではありませんが、消費メモリも増加します.したがってalertオブジェクトの解放も必要です.
これが私たちが紹介したメモリ漏洩問題の解決方法であり、実際にはメモリ漏洩は極めて複雑な問題であり、ツールの使用は一方であり、経験は他方である.経験を向上させ、ツールを活用することがメモリの漏洩を解決する根本です.