iOS FMDB извлекает около трех миллионов элементов: завершается из-за проблем с памятью
Недавно я работаю над приложением о sqlite. Я использовал FMDB (2.6.2), а iOS - 10.2.0 . В базе данных около трех миллионов предметов. И у каждого предмета есть три колонны:id
name
logo
,
При отображении всех данных на пользовательском интерфейсе, требования приложения унесены:
- Вы не можете использовать способ получения большего количества данных (так же, как использовать
UITableView
или жеUICollectionView
прокрутите вниз, чтобы загрузить больше, но вы все еще можете использоватьUITableView
или жеUICollectionView
) - Пользовательский интерфейс должен быть очень плавным при прокрутке
- Не вызывает переполнение памяти
Согласно требованиям, я проверяю некоторые условия.
Я могу удовлетворить первое и второе требование. Но последнее, я обнаружил, что когда вы выбираете все три миллиона элементов из БД один или много раз, это все равно может вызвать переполнение памяти.
Вот мой код для извлечения данных в фоновой очереди:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (_usersArrM.count < _countNum)
{
NSUInteger offset = _usersArrM.count + usersFromDBOffsetCount;
if (offset > _countNum)
{
offset = _countNum - _usersArrM.count;
}
else
{
offset = usersFromDBOffsetCount;
}
NSString *sql = [NSString stringWithFormat:@"select * from user limit %zd, %zd", _usersArrM.count, offset];
[_queue inDatabase:^(FMDatabase *db) {
FMResultSet *userModelRS = [db executeQuery:sql];
while (userModelRS.next)
{
AndyUserModel *userModel = [[AndyUserModel alloc] init];
userModel.Id = [userModelRS intForColumn:@"id"];
userModel.name = [userModelRS stringForColumn:@"name"];
userModel.logo = [userModelRS stringForColumn:@"logo"];
[_usersArrM addObject:userModel];
}
[userModelRS close];
}];
[_queue close];
}
});
Подсказки:
_usersArrM
:NSMutableAarray
источник данныхUITableView
_countNum
: количество предметов в дБusersFromDBOffsetCount
:static NSUInteger const usersFromDBOffsetCount = 2000;
_queue
:_queue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
- скачать БД: http://okufme2fh.bkt.clouddn.com/test.db.zip
Я думаю, проблема, которая вызывает переполнение памяти _queue
, даже если [_queue close]
, некоторая память о БД не может быть освобождена правильно. И результат в том, что когда цикл несколько раз, приложение закрывается из-за проблемы с памятью.
Есть ли один способ полностью освободить память БД, когда закончится один цикл. Или как правильно удовлетворить эти требования для этого приложения.
Благодарю.
1 ответ
В какой-то момент, независимо от того, насколько хороша ваша структура данных, само выделение памяти приведет к сбою любого оборудования, недостаточно мощного для его обработки. Вы можете попытаться извлечь данные, которые вы пытаетесь получить (т.е.
SELECT specific_col_1, specific_col_2, ... FROM table WHERE conditions
где specific_col_i
является низким значением потребления памяти в среднем.
Другой гарантией будет использование OFFSET
а также LIMIT
чтобы ограничить объем данных, которые вы извлекаете из базы данных в любой момент времени:
SELECT specific_col_1, specific_col_2, ... FROM table WHERE conditions LIMIT x OFFSET j
где x - это безопасное количество записей, которые нужно извлечь и обработать за один раз, а j - индекс последнего числа найденных строк. Возможно, вам придется "играть" со значениями x
а также j
,
Скорее всего, вам придется использовать интеллектуальный алгоритм зацикливания, чтобы выборочно "вводить и обрабатывать" все эти записи. И вы можете хранить партии, которые вы получаете от циклов, в сторону, в другой таблице / базе данных, если это необходимо (точно не знаете, что вам нужно для обработки данных, когда данные вводятся или после ввода данных).
Наконец, вы можете найти LabQLite полезным. Это библиотека, которую я разработал для работы с SQLite в приложении для iOS. LabQLite Model Generator - это созданный мной генератор моделей, который позволит вам рассматривать ваши таблицы и представления как классы в Objective-C (или Swift, если вы выполняете код взаимодействия)). В LabQLite также имеется множество средне- и низкоуровневых методов контроллера баз данных, которые могут помочь в уточнении процесса циклирования / пакетирования, о котором я упоминал выше.