Мой вопрос в том, что Core Data и память не будут выпущены. Я делаю процесс синхронизации, импортируя данные из WebService, который возвращает json. Я загружаю в память данные для импорта, циклирования и создания NSManagedObjects. Импортируемые данные должны создавать объекты, имеющие отношения к другим объектам, всего около 11 000. Но для того, чтобы изолировать проблему, я сейчас создаю элементы первого и второго уровня, оставляя связь вне, это 9043 объекта.
Я начал проверять объем используемой памяти, потому что приложение терпело крах в конце процесса (с полным набором данных). Первая проверка памяти после загрузки в память json, так что измерение действительно учитывает только создание и вставку объектов в Core Data. Для проверки используемой памяти используется этот код (источник)
-(void) get_free_memory { struct task_basic_info 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, &size); if( kerr == KERN_SUCCESS ) { NSLog(@"Memory in use (in bytes): %f",(float)(info.resident_size/1024.0)/1024.0 ); } else { NSLog(@"Error with task_info(): %s", mach_error_string(kerr)); } }
Моя настройка:
- 1 Постоянный координатор магазина
- 1 Main ManagedObjectContext (MMC) (NSMainQueueConcurrencyType используется для чтения (только чтения) данных в приложении)
- 1 Background ManagedObjectContext (BMC) (NSPrivateQueueConcurrencyType, undoManager установлен на nil, используется для импорта данных)
BMC не зависит от MMC, поэтому BMC не является дочерним контекстом MMC. И они не разделяют какой-либо родительский контекст. Мне не нужно BMC уведомлять изменения в MMC. Поэтому BMC необходимо создавать/обновлять/удалять данные.
Plaform:
- iPad 2 и 3
- iOS, я тестировал установку цели развертывания на 5.1 и 6.1. Нет разницы.
- XCode 4.6.2
- ARC
Проблема: Импортируя данные, используемая память не перестает увеличиваться, и iOS, похоже, не может разрядить память даже после завершения процесса. Что, в случае увеличения образца данных, приводит к предупреждению памяти и после закрытия приложения.
Исследование:
-
Документация Apple
-
Хорошее описание пунктов, которые нужно иметь в виду при импорте данных в Core Data (qaru.site/info/58752/...)
-
Выполненные тесты и анализ выпуска памяти. Кажется, у него такая же проблема, как у меня, и он отправил отчет Apple Bug, но от Apple еще не ответил. (Источник)
-
Импорт и отображение больших наборов данных (Источник)
-
Указывает лучший способ импортировать большой объем данных. Хотя он упоминает:
"Я могу импортировать миллионы записей в стабильной 3 МБ памяти без вызов - reset."
Это заставляет меня думать, что это может быть как-то возможно? (Источник)
Тесты:
Пример данных: создание всего 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
}
Measurment:
Он идет от 16,97 МБ до 30 МБ, после синхронизации он сокращается до 28 МБ. Повторяя вызов get_memory каждые 5 секунд, память сохраняется на уровне 28 МБ.
Другие тесты без везения:
- воссоздание постоянного хранилища, как указано в исследовании 2) не имеет эффекта
- проверено, чтобы поток немного подождал, чтобы восстановить восстановление памяти, пример 4)
- установочный контекст для nil после всего процесса
- Выполнение всего процесса без сохранения контекста в любой момент (потере информации). Это на самом деле дало в результате меньшее количество памяти, оставив ее на уровне 20 МБ. Но он все еще не уменьшается и... Мне нужна информация, хранящаяся:)
Возможно, мне что-то не хватает, но я действительно много тестировал, и после выполнения рекомендаций я ожидал, что память снова уменьшится. Я запустил инструменты Allocations, чтобы проверить рост кучи, и, похоже, это тоже хорошо. Также нет утечек памяти.
У меня заканчиваются идеи по тестированию/настройке... Я был бы очень признателен, если бы кто-нибудь мог помочь мне с идеями о том, что еще я мог бы проверить, или, возможно, указывая на то, что я делаю неправильно. Или это просто так, как это должно работать... что я сомневаюсь...
Спасибо за любую помощь.
ИЗМЕНИТЬ
Я использовал инструменты для профилирования использования памяти с помощью шаблона Activity Monitor, и результат, показанный в "Реальное использование памяти", такой же, как тот, который печатается в консоли с помощью get_free_memory
, и память все еще никогда не кажется чтобы освободиться.