9

この問題があります。CoreDataに画像のデータベースがあります。すべての画像(約80MB)をフェッチし、NSMutableArrayに配置します。オブジェクトは正しく障害が発生しています。

NSArray *fetchResults = [self.managedObjectContext executeFetchRequest:request error:&error];
self.cache = [NSMutableArray arrayWithArray:fetchResults];
for (ImageCache *imageObject in self.cache) {
    NSLog(@"Is fault? %i", [imageObject isFault]);
}

ログを読むと、オブジェクトはすべて正しく障害が発生していることがわかります。ただし、Instrumentsを使用すると、80MBのメモリが使用されていることがわかります。これが、Core Dataが結果をキャッシュし、必要なときにメモリを解放する理由だと思います。しかし(そしてこれが私の「問題」です)、メモリ警告をシミュレートしても何も起こりません!80MBはそこに残ります。

機器-割り当てを見ると、80MBは多くのMallocで使用されています:(例)

グラフカテゴリライブバイト数#リビング#一時的な全体バイト数#全体#割り当て(ネット/全体)0マロック176,00 KB 8,59 MB 50 57 18,39 MB 107%0.00、%0.000マロック200,00KB 8,20 MB 42460 98,05 MB 502%0.00、%0.04 0 Malloc 168,00 KB 7,05 MB 43 19 10,17 MB 62%0.00、%0.00

これは、コールツリー全体の画像へのリンクです:https ://www.dropbox.com/s/du1b5a5wooif4w7/Call%20Tree.png

何か案は?ありがとう

4

2 に答える 2

9

わかりました、なぜそれが起こるのか理解しました。エンティティに対してフェッチ要求を行うと、障害が有効になっている場合でも、そのエンティティのすべてのデータがメモリにロードされます。大きなバイナリデータを含みます。これは、多くの方法を使用して解決できます。

1-これを設定NSFetchRequest[request setIncludesPropertyValues:NO]; NOに設定すると、データはすぐにキャッシュに読み込まれませんが、要求があった場合にのみ読み込まれます(プロパティにアクセスして障害が発生した場合)。ただし、これには「問題」があります。プロパティを再度フォールトしようとしても(すぐに必要ではなく、を使用してメモリを解放したいため[self.managedObjectContext refreshObject:object mergeChanges:NO];)、メモリは解放されません。managedObjectContextがリセットされるまで、キャッシュは存続します。

これの方が良い:

2-データを個別のエンティティに分割できます。私の場合、URLと画像データの2つのプロパティしかありませんでした。データを1:1の関係で2つのエンティティ(imagecacheとimagedata)に分割しました。「imagecache」エンティティのすべての行に対してfetchRequestを作成し(urlプロパティを使用)、前のソリューションと同様に、メモリはキャッシュされませんでした。プロパティimagecache.relationship.imageに正しく障害が発生しました。このプロパティにアクセスすると、障害が発生し、キャッシュがいっぱいになりました。ただし、この場合、[self.managedObjectContext refreshObject:object mergeChanges:NO];「imagecache」オブジェクト(「father」オブジェクト)を実行すると、キャッシュとメモリがすぐに解放され、imagecache.relationship.imageプロパティが再び失敗します。重要:「子」オブジェクトに対しては実行しないでください。実行する場合は[self.managedObjectContext refreshObject:object.relationship mergeChanges:NO]、何らかの理由でキャッシュが解放されません。

3-これは主に学術的な質問であり、この問題の本当の「終日」の解決策(パフォーマンスの向上と頭痛の軽減)は、コアデータデータベース内にビッグデータを保存しないようにすることです。データをファイルとして保存し、参照(ファイルパス)のみを保存するか、iOS 5では、コアデータモデル内の任意の「データ」プロパティに「外部ストレージを使用」を設定することができます。これはあなたのためにすべての仕事をします。

于 2012-09-08T16:17:31.807 に答える
0

より少ないオブジェクトをバッチでメモリにロードする必要があると思います。

coredataによって解放されたメモリは舞台裏で発生し、プログラムする必要はありません。悪いニュースは、それが舞台裏で起こり、したがって「魔法のように」記憶をかみ砕くことができるということです。

それを回避する方法はたくさんあります。たとえば、述語を使用して、絶対に必要な行のみを選択します。すべてをフェッチしてからリストを1つずつ確認するために、一般的な呼び出しを行わないでください。一般的な呼び出しを実行し、CoreDataがすべてのオブジェクトを読み込もうとすると、クラッシュする可能性が高くなります。

于 2012-09-06T08:37:31.803 に答える