4

コア データ データベースに cca 100 000 レコードを挿入しています。データベースには 3 つのエンティティが含まれています。Player、Club、PlayerClub エンティティの関係は次のとおりです: Player<-->>PlayerClub<<-->Club PlayerClub への挿入中に、約 50,000 レコードが挿入された後、大量のメモリ消費と速度の低下に気付きました。PlayerClub には一意の値しかないため、レコードが更新されることはありません。テスト上の理由から、Player テーブルと Club テーブルを空にして、プログラムを再度実行しました。速度の低下はありませんでしたが、メモリの消費量が再び膨大になりました。これはコードです:

    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
    [context setPersistentStoreCoordinator:ap.persistentStoreCoordinator];
    [context setUndoManager:nil];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"PlayerClub"
                                              inManagedObjectContext:context];

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entity];

    NSEntityDescription *entityKlubovi = [NSEntityDescription entityForName:@"Club" inManagedObjectContext:context];
    NSFetchRequest *requestKlubovi = [[NSFetchRequest alloc] init];
    [requestKlubovi setEntity:entityKlubovi];
    [requestKlubovi setFetchLimit:1];

    NSEntityDescription *entityIgraci = [NSEntityDescription entityForName:@"Player" inManagedObjectContext:context];
    NSFetchRequest *requestIgraci = [[NSFetchRequest alloc] init];
    [requestIgraci setFetchLimit:1];
    [requestIgraci setEntity:entityIgraci];

    for (int i=0; i<[parsedKlubIgraci count]; i++) {
        @autoreleasepool {
            KlubIgrac *klubIgrac = [[KlubIgrac alloc] initWithEntity:entity insertIntoManagedObjectContext:context];

            klubIgrac.iD = p.id;

            //... add some othe properties

            variables = [NSDictionary dictionaryWithObject:p.igracID forKey:@"ID"];
            localPredicate = [predicateIgraci predicateWithSubstitutionVariables:variables];
            [requestIgraci setPredicate:localPredicate];
            klubIgrac.igrac = [self DohvatiIgracZaIgracId:p.igracID cntx:context request:requestIgraci predicate:localPredicate];

            variables = [NSDictionary dictionaryWithObject:p.klubID forKey:@"ID"];
            localPredicate = [predicateKlubovi predicateWithSubstitutionVariables:variables];
            [requestKlubovi setPredicate:localPredicate];
            klubIgrac.klub = [self DohvatiKlubZaKlubId:p.klubID cntx:context request:requestKlubovi predicate:localPredicate];
        }

    }
+(Club *)DohvatiKlubZaKlubId:(int)klubid cntx:(NSManagedObjectContext *)context    

    request:(NSFetchRequest *)request predicate:(NSPredicate *)predicate
{
    @autoreleasepool {
        NSError *error;
        NSArray *arTmp;
        arTmp = [context executeFetchRequest:request error:&error];
        Club *klub;
        if(arTmp != nil && [arTmp count]){
            return [arTmp objectAtIndex:0];
        }
    }

}

DohvatiIgracZaIgracId メソッドは基本的に DohvatiKlubZaKlubId と同じメソッドなので載せません。このコードは約 100 000 回呼び出されます。以前のメモリ消費量は約 150 MB です。650 MB が終了した後。そのため、コンテキストを保存せず、データベースから何も取得せずに 500 MB を消費すると、テーブルが空になります。コメントしたら

arTmp = [context executeFetchRequest:request error:&error];

DohvatiIgracZaIgracId および DohvatiKlubZaKlubId メソッドの行を変更すると、メモリ消費量が 200 MB に減少します。したがって、何もしないコード行の差は 400MB です。これはできません。誰にでもアイデアはあります。しばらくすると、アプリが 2.5 GB を超えて消費します。

測定はシミュレーターで行われたため、後でプリロードするデータベースを構築する必要があるため、速度が重要です:) ...事前にThx

4

1 に答える 1

14

コンテキストを保存せずに

これは、経験豊富な Core Data 開発者が「なんてこった」と言う質問の一部です。それがあなたの最大の問題です。定期的に変更を保存します。50 エントリごと、または 100 エントリごとなどですが、何をするにしても、完了するまで待たないでくださいこれらすべてのオブジェクトを未保存の変更としてメモリに保持することを Core Data に強制しています。これが、メモリの問題を抱えている最大の理由です。

あなたが考慮すべき他のいくつかのこと:

  • 一度に 1 つずつオブジェクトを取得しないでください。フェッチは比較的高価です。10 万個のインスタンスを実行し、それぞれを一度に 1 つずつ取得すると、コードはほぼすべての時間を取得の実行に費やします。50 ~ 100 のバッチで取得します (速度とメモリ使用量の最適なバランスを得るために数を調整できます)。1 つのバッチを処理し、バッチの最後に変更を保存します。

  • フェッチされたオブジェクトの操作が完了したら、管理オブジェクト コンテキストに完了を伝えます。これを行うには、2 番目の引数としてrefreshObject:mergeChanges:withを呼び出します。NOこれは、オブジェクトに使用している内部メモリを解放できることをコンテキストに伝えます。これにより、保存されていないオブジェクトの変更が失われますが、変更を行っていない場合、失うものは何もありません。

  • PlayerClubエンティティを完全に削除することを検討してください。Core Data は、多対多の関係をサポートしています。この種のエンティティはほとんど役に立ちません。SQL ではなく Core Data を使用しているため、エンティティ タイプをそのまま設計しないでください。

于 2013-11-13T17:33:55.090 に答える