GCD-> blocks-> C ++ - > SQLCipher:Sqlite3MemMalloc内存在任务完成后不会释放

时间:2015-05-08 11:41:43

标签: c++ ios objective-c memory-management grand-central-dispatch

我正在研究数据库应用程序并使用SQLCipher进行数据库加密。我正在使用GCD串行队列进行所有数据库相关操作和手动内存管理。下面是我的数据库相关操作的代码片段。我有更多方法,例如saveRecordData:,它为不同类型的记录调用executeOnGCD:

-(void)saveRecordData:(NSArray *)dataObjects{
    [self executeOnGCD:^{
        std::vector<RecordData> list;

        for(id object in dataObjects){
            RecordData recordDataObject(/*create c++ data object*/)
            list.push_back(recordDataObject);
        }

        DataBaseManager::GetInstance()->saveData(list);
    }];
}

-(void)executeOnGCD:(void (^)())block{
    __block UIBackgroundTaskIdentifier task = UIBackgroundTaskInvalid;

    task = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [[UIApplication sharedApplication] endBackgroundTask:task];
        task=UIBackgroundTaskInvalid;
    }];

    void (^executionBlock)() = ^(){
        @autoreleasepool {
            block();
            [[UIApplication sharedApplication] endBackgroundTask:task];
            task=UIBackgroundTaskInvalid;
        }
    };
    //dataManagerQueue is serial queue.
    dispatch_async(self.dataManagerQueue, executionBlock);
}

这里DataBaseManager是执行实际数据库插入的C ++类。 DataBaseManager的saveData实现如下。

void saveData(std::vector<RecordData> list) {
    for(RecordData record : list)
    {
        sqlite3_stmt * statement = nullptr;

        if(sqlite3_prepare_v2(m_dbConnection, INSERT_STATEMENT, -1, &statement, NULL) == SQLITE_OK)
        {
            //Bind parameters
            int index = sqlite3_bind_parameter_index(statement, COLUMN1);
            sqlite3_bind_int(statement, index, value1);

            index = sqlite3_bind_parameter_index(statement, COLUMN2);
            sqlite3_bind_int(statement, index, value2);

            /*Bind other parameters*/

            sqlite3_step(statement);
        }
        sqlite3_finalize(statement);
    }
}

当我的应用程序使用saveData函数保存80k +记录时,操作开始和操作结束之间存在内存分配差异。仪器表明仍有SQLCipher分配的内存,即使在5分钟的操作完成后也没有释放。如下图所示,在操作开始时,内存分配为1.90mb,完成后任务内存减少到6.6mb不到1.90mb

enter image description here

一旦操作完成,内存减少非常缓慢,大约需要6分钟,以便将内存从20mb减少到6.6mb。

我的问题是

1)为什么在完成任务后内存没有下降到~1.90mb?这是否与在GCD中使用c ++对象有关?

2)为什么需要大约6分钟才能将内存从20mb减少到6.6mb? GCD会慢慢释放内存吗?

3)我还看到libdispatch.dylb分配的_dispatch_alloc_try_create_heap块,在操作完成后也没有释放。

4)我是否在executeOnGCD:方法中使用了正确的嵌套块方法?

1 个答案:

答案 0 :(得分:0)

我不知道你所处的情况的确切答案,但我有一些建议,而且它们不仅仅适用于评论......

这里你要做的是查看完成后6分钟内发生的免费事件的堆栈跟踪。这应该给你一些关于如何安排解除分配的线索。似乎有一些后台线程正在进行清理。获取这些堆栈跟踪应该允许您在代码中搜索最初安排清理的位置,并且应该提供您寻求的答案。

该图的向上和向下斜率之间的紧密相似性使得 me 认为(概念上)在最后一次使用该对象时启动了一个计时器,并且有一些机制可以在一些对象之后重新使用它们。不活动的时期。这可能是通过在malloc时间使用某个注册表注册对象来实现的,然后在每次使用对象时更新lastUsed字段,然后定期进程遍历列表并有效地说“释放所有避开的对象”已被用于X时间。“这可能存在以提供某种隐式缓存机制。

我不确定这一点,但这似乎是一个可能的解释。