iOS中的Sqlite内存问题

iOS中的Sqlite内存问题,ios,memory,memory-management,sqlite,Ios,Memory,Memory Management,Sqlite,我花了几个小时试图解决这个问题,但我已经放弃了;我不知道怎么了 在我的应用程序中,我执行嵌套SQL操作以正确设置所有对象。出于某种原因,有时候sqlite3对象没有得到正确的释放,导致内存急剧增加。我理解正确使用sql3_close和sql3_finalize是一个问题。然而,正如你将看到的,我认为我正确地使用了它们 以下是问题的根源: - (NSArray *) getAllSessions { if (sqlite3_open(dbPath, &db) == SQLITE_O

我花了几个小时试图解决这个问题,但我已经放弃了;我不知道怎么了

在我的应用程序中,我执行嵌套SQL操作以正确设置所有对象。出于某种原因,有时候sqlite3对象没有得到正确的释放,导致内存急剧增加。我理解正确使用sql3_close和sql3_finalize是一个问题。然而,正如你将看到的,我认为我正确地使用了它们

以下是问题的根源:

- (NSArray *) getAllSessions {
    if (sqlite3_open(dbPath, &db) == SQLITE_OK) { 
        if (sqlite3_prepare_v2(db, query_stmt, -1, &statement, NULL) == SQLITE_OK) {
            while (sqlite3_step(statement) == SQLITE_ROW) {

                //I found out that doing something like that
                //toAdd.in_loc = [self getIndoorLocationWithId:[NSNumber numberWithInt:(int)sqlite3_column_int(statement, 6)]];
                //messes the memory up all the time
                //but doing that works OK:
                NSNumber *_id = [[NSNumber alloc]  initWithInt:(int) sqlite3_column_int(statement, 5)];
                toAdd.out_loc = [self getOutdoorLocationWithId:_id];
                [_id release];

                //So I did the same with the second one, but this one messes memory up:
                NSNumber *id2 = [[NSNumber alloc] initWithInt:(int)sqlite3_column_int(statement, 6)];
                toAdd.in_loc = [self getIndoorLocationWithId:id2];
                [id2 release];
            }
            sqlite3_finalize(statement);
        }
        sqlite3_close(db);
    } 
}
因此,这里是一个混乱的记忆:

- (IndoorLocation *) getIndoorLocationWithId:(NSNumber *) locId {
    if (sqlite3_open([databasePath UTF8String], &db) == SQLITE_OK) { 
        if (sqlite3_prepare_v2(db, query_stmt, -1, &statement, NULL) == SQLITE_OK) {
            while (sqlite3_step(statement) == SQLITE_ROW) {  
                //if I comment the thing below it works
                NSNumber *_id = [[NSNumber alloc]  initWithInt:(int) sqlite3_column_int(statement, 5)];
                toReturn.outLoc = [self getOutdoorLocationWithId:_id];
                [_id release];

            }
            sqlite3_finalize(statement);
        }
        sqlite3_close(db);
    }
}
因此,在一个混乱的内存中,我使用了与第一次完全相同的函数(getOutdoorLocationwithId),同样的方式,但它不起作用,sqlite3对象不能正确释放


我希望你能理解我的问题,这让我快发疯了

在这样的单用户应用程序中,无需不断地打开和关闭。这与基于服务器的应用程序不同,在基于服务器的应用程序中,您与多个用户建立连接池,而保持连接会破坏连接池并损害可伸缩性。在手机应用程序中,打开并保持打开状态。完成后关闭它。至少,在递归调用中这样做

更糟糕的是,您在递归调用中打开和关闭—只需让它保持打开状态

此外:

  • 您没有检查finalize的返回代码
  • 您没有检查close的返回代码
  • 您正在准备(编译)语句,但没有将它们保存在已保存语句上的off-call reset并再次执行
考虑使用FMDB——它是一个很好的包装器

顺便说一句,这里有一个更丰富和更持久的密切,但不要用它在每一个电话。当你结束或你的应用程序进入后台时关闭它。。。这是我的,类似于fmdb的功能

- (void)close
{
    if (_sqlite3)
    {
        ENInfo(@"closing");
        [self clearStatementCache];

        int rc = sqlite3_close(_sqlite3);
        ENDebug(@"close rc=%d", rc);

        if (rc == SQLITE_BUSY) 
        { 
            ENError(@"SQLITE_BUSY: not all statements cleanly finalized");

            sqlite3_stmt *stmt; 
            while ((stmt = sqlite3_next_stmt(_sqlite3, 0x00)) != 0) 
            {
                ENDebug(@"finalizing stmt");
                sqlite3_finalize(stmt); 
            }

            rc = sqlite3_close(_sqlite3);
        }

        if (rc != SQLITE_OK)
        {
            ENError(@"close not OK.  rc=%d", rc);
        }

        _sqlite3 = NULL;
    }
}
我遇到了同样的问题。 当我使用并打开FMDB时,它工作正常。但在其他回调中,它失败并引发了“关闭泄漏语句”异常。最后我发现这是因为我保留了[FMDatabase databaseWithPath:dbPath]中的指针,而指针是一个自动释放对象。我通过以下方式解决了问题:

FMDatabase *db = [[FMDatabase databaseWithPath:dbPath] retain];
当您要关闭数据库时: db[关闭]; [数据库释放]; db=零


这样,您就不必总是为每个操作打开和关闭数据库,数据库应该是一个管理器对象。当管理器启动时,数据库始终处于打开状态,直到管理器停止。

数据库已经在getAllSessions中打开,重新打开然后关闭会把它搞砸。然后在这两种方法中都声明了一个返回类型,但没有返回任何内容。xcode没有对此抱怨吗?我没有包含所有代码来保持简单。关于你的第一点,我同意,但是为什么第一次有效而第二次无效呢?一直以来都是令人敬畏的开局和收局,非常感谢!