简体   繁体   English

iOS FMDB获取约三百万个项目:由于内存问题而终止

[英]iOS FMDB fetch about three million items: Terminate due to memory issue

Recently I am working on an app about sqlite. 最近,我正在开发有关sqlite的应用程序。 I used FMDB (2.6.2) and iOS is 10.2.0 . 我使用了FMDB(2.6.2),iOS是10.2.0。 There are about three million items in an database. 数据库中大约有三百万个项目。 And every item has three colomns: id name logo . 每个项目都有三个列: id name logo

When showing all the data on UI, the requiremens of the app is blow: 当在UI上显示所有数据时,该应用程序的要求很差:

  • You can not use the way of fetching more data (just like use UITableView or UICollectionView scroll to bottom to load more,but you still can use UITableView or UICollectionView ) 您不能使用获取更多数据的方式(就像使用UITableViewUICollectionView滚动到底部以加载更多数据一样,但是您仍然可以使用UITableViewUICollectionView
  • UI must be very smooth when you scroll 滚动时,UI必须非常流畅
  • Don't cause memory overflow 不要引起内存溢出

According to the requirments, I test some conditions. 根据要求,我测试了一些条件。

I can satisfy the first and sceond requirement. 我可以满足第一个和第二个要求。 But the last one ,I find when you fetch all the three million items from db once or many times, it still can cause memory overflow. 但是最后一个,我发现当您一次或多次从db获取所有三百万个项目时,它仍然可能导致内存溢出。

Here is my code to fetch data in background queue: 这是我的代码,用于在后台队列中获取数据:

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];
    }
});

Tips: 提示:

  • _usersArrM : a NSMutableAarray the datasource of UITableView _usersArrM :一个NSMutableAarray UITableView的数据源
  • _countNum : the nums of items in db _countNum :db中的项目数
  • usersFromDBOffsetCount : static NSUInteger const usersFromDBOffsetCount = 2000; usersFromDBOffsetCountstatic NSUInteger const usersFromDBOffsetCount = 2000;
  • _queue : _queue = [FMDatabaseQueue databaseQueueWithPath:dbPath]; _queue_queue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
  • db download: http://okufme2fh.bkt.clouddn.com/test.db.zip 资料库下载: http : //okufme2fh.bkt.clouddn.com/test.db.zip

I guess the issue that causes memory overflow is _queue , even though [_queue close] , some memory about db can`t be released correctly . 我想导致内存溢出的问题是_queue ,即使[_queue close] ,也无法正确释放有关db的某些内存。 And the reult is when loop some times, app terminate due to memory issue. 结果是当循环几次时,由于内存问题应用程序终止。

Is there one way to release the memory of db completely when one loop is finished . 一个循环完成后,是否有一种方法可以完全释放db的内存。 Or what is the correct way to satisfy these requirements for this app. 或满足此应用程序这些要求的正确方法是什么。

Thanks. 谢谢。

At some point, no matter how good your data framework is, sheer memory allocation will crash any hardware not powerful enough to handle it. 在某个时候,无论您的数据框架多么出色,纯粹的内存分配都会使任何功能不强大的硬件崩溃。 You could try hollowing out the data you're trying to retrieve (ie 您可以尝试掏空要检索的数据(即

SELECT specific_col_1, specific_col_2, ... FROM table WHERE conditions

where specific_col_i is a low memory consumption value on average. 其中, specific_col_i是平均较低的内存消耗值。

Another safeguard would be to use OFFSET and LIMIT to limit the amount of data you pull from the database at any given time: 另一个保护措施是在任何给定时间使用OFFSETLIMIT限制您从数据库中提取的数据量:

SELECT specific_col_1, specific_col_2, ... FROM table WHERE conditions LIMIT x OFFSET j

where x is a safe number of records to pull and process at one time, and j is the index of the last number of rows retrieved. 其中x是一次可提取和处理的安全记录数,而j是最后检索到的行数的索引。 You may have to "play" with the values of x and j . 您可能必须“玩” xj的值。

You will likely have to use an intelligent looping algorithm to selectively 'bring in and process' all of those records. 您可能必须使用智能循环算法来选择性地“引入并处理”所有这些记录。 And, you could store the batches you get from the loops off to the side in another table/database if that is needed (not sure exactly what your data processing needs are as data are being brought in or after data are brought in). 并且,如果需要,您可以将从循环中获得的批处理存储到另一个表/数据库中(不确定要在导入数据时还是导入数据后确切地处理数据的需求)。

Lastly, you may find LabQLite helpful. 最后,您可能会发现LabQLite很有帮助。 This is a library I've developed for handling SQLite in an iOS app. 这是我为在iOS应用中处理SQLite而开发的库。 LabQLite Model Generator is a model generator I created that would allow you to treat your tables and views as classes in Objective-C (or Swift if you do interop code)). LabQLite模型生成器是我创建的模型生成器,它允许您将表和视图视为Objective-C中的类(如果执行互操作代码,则将其视为Swift)。 LabQLite also has plenty of mid- and low-level database controller methods that might help with refining the looping/batching process I mentioned above. LabQLite还具有大量的中低级数据库控制器方法,这些方法可能有助于完善我上面提到的循环/分批处理过程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM