私の質問は、Core Data とメモリが解放されていないことについてです。JSON を返す WebService からデータをインポートする同期プロセスを実行しています。インポートするデータをメモリにロードし、ループして NSManagedObjects を作成します。インポートされたデータは、他のオブジェクトとの関係を持つオブジェクトを作成する必要があり、合計で約 11.000 あります。しかし、問題を特定するために、私は現在、第 1 レベルと第 2 レベルのアイテムのみを作成し、関係を除外しています。これらは 9043 オブジェクトです。
アプリがプロセスの最後に (完全なデータ セットで) クラッシュしたため、メモリ使用量のチェックを開始しました。最初のメモリ チェックは、JSON をメモリにロードした後で行われるため、測定では、オブジェクトの作成と Core Data への挿入のみが考慮されます。使用されているメモリを確認するために使用するのは、このコードです ( source )
-(void) get_free_memory { struct task_basic_info 情報; mach_msg_type_number_t size = sizeof(info); kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO、 (task_info_t)&info, &サイズ); if( カー == KERN_SUCCESS ) { NSLog(@"使用中のメモリ (バイト単位): %f",(float)(info.resident_size/1024.0)/1024.0 ); } そうしないと { NSLog(@"task_info() のエラー: %s", mach_error_string(kerr)); } }
私のセットアップ:
- 常駐ストア コーディネーター 1 名
- 1 Main ManagedObjectContext (MMC) (アプリ内のデータの読み取り (読み取りのみ) に使用される NSMainQueueConcurrencyType)
- 1 バックグラウンド ManagedObjectContext (BMC) (NSPrivateQueueConcurrencyType、undoManager は nil に設定、データのインポートに使用)
BMC は MMC から独立しているため、BMC は MMC の子コンテキストではありません。また、それらは親コンテキストを共有しません。変更を MMC に通知するのに BMC は必要ありません。したがって、BMC はデータを作成/更新/削除するだけで済みます。
プラットフォーム:
- iPad 2 および 3
- iOS では、デプロイ ターゲットを 5.1 および 6.1 に設定してテストしました。違いはありません
- X コード 4.6.2
- アーク
問題: データをインポートすると、使用メモリの増加が止まらず、プロセスの終了後も iOS がメモリを排出できないようです。これは、データ サンプルが増加した場合にメモリ警告につながり、アプリの終了後に発生します。
リサーチ:
アップルのドキュメント
Core Data にデータをインポートする際の注意点のまとめ ( Stackoverflow )
実行されたテストとメモリ リリースの分析。彼は私と同じ問題を抱えているようで、Apple からまだ応答がなく、Apple Bug レポートを送信しました。(ソース)
大きなデータ セットのインポートと表示 ( Source )
大量のデータをインポートする最適な方法を示します。彼は言及していますが:
「-reset を呼び出さずに、安定した 3 MB のメモリに何百万ものレコードをインポートできます。」
これは、これがどういうわけか可能かもしれないと私に思わせますか?(ソース)
テスト:
データ サンプル: 合計 9043 個のオブジェクトを作成します。
- ドキュメントに「高価」であると記載されているため、関係の作成をオフにしました
- フェッチは行われていません
コード:
- (void)processItems {
[self.context performBlock:^{
for (int i=0; i < [self.downloadedRecords count];) {
@autoreleasepool
{
[self get_free_memory]; // prints current memory used
for (NSUInteger j = 0; j < batchSize && i < [self.downloadedRecords count]; j++, i++)
{
NSDictionary *record = [self.downloadedRecords objectAtIndex:i];
Item *item=[self createItem];
objectsCount++;
// fills in the item object with data from the record, no relationship creation is happening
[self updateItem:item WithRecord:record];
// creates the subitems, fills them in with data from record, relationship creation is turned off
[self processSubitemsWithItem:item AndRecord:record];
}
// Context save is done before draining the autoreleasepool, as specified in research 5)
[self.context save:nil];
// Faulting all the created items
for (NSManagedObject *object in [self.context registeredObjects]) {
[self.context refreshObject:object mergeChanges:NO];
}
// Double tap the previous action by reseting the context
[self.context reset];
}
}
}];
[self check_memory];// performs a repeated selector to [self get_free_memory] to view the memory after the sync
}
測定:
16.97 MB から 30 MB になり、同期後は 28 MB に減少します。get_memory 呼び出しを 5 秒ごとに繰り返すと、メモリが 28 MB に維持されます。
運がない他のテスト:
- 研究で示されているように永続ストアを再作成しても効果はありません 2)
- メモリが復元されるかどうかを確認するためにスレッドを少し待機させるようにテストしました。例 4)
- プロセス全体の後にコンテキストを nil に設定する
- どの時点でもコンテキストを保存せずにプロセス全体を実行します(そのため情報が失われます)。実際には、結果として維持されるメモリ量が少なくなり、20 MB のままになりました。しかし、それでも減少せず...情報を保存する必要があります:)
多分私は何かが欠けているかもしれませんが、私は実際に多くのことをテストしました.ガイドラインに従った後、メモリが再び減少することが予想されます. Allocations インストゥルメントを実行してヒープの成長を確認しましたが、これも問題ないようです。また、メモリリークもありません。
テスト/調整するアイデアが不足しています...他に何をテストできるか、または私が間違っていることを指摘してくれる人がいれば、本当に感謝しています。それとも、それがどのように機能するはずなのか、そのようなものです...私は疑問に思っています...
助けてくれてありがとう。
編集
計測器を使用して、アクティビティ モニター テンプレートでメモリ使用量をプロファイリングしました。「実際のメモリ使用量」に表示される結果は、コンソールに出力された結果と同じでget_free_memory
あり、メモリはまだ解放されていないようです。