查询中的内存分配

时间:2012-01-09 12:04:41

标签: objective-c ios memory-management sqlite

我有一个使用数据查询并在UITableView中显示它们的应用程序。到目前为止一切顺利,我可以访问SQLite数据库并在表中显示数据但是在我的应用程序内存短暂使用后收到警告通知。等级= 1并关闭。在搜索中使用分析工具我注意到我的应用数据消耗了大量合理的内存。

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section  {

    tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;

    return [count count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  {

    iMapDadosClientes *dadosClientes = (iMapDadosClientes *)[count objectAtIndex:indexPath.row];

    NSString *myIdent = @"myIdent";

    iMapGrid *grid = (iMapGrid *)[tableView dequeueReusableCellWithIdentifier:myIdent];

    tvDadosClientes.autoresizesSubviews = YES;

    if (grid == nil) {

        grid = [[[iMapGrid alloc] initWithFrame:CGRectZero reuseIdentifier:myIdent] autorelease];

        UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(0.0, 0, 50.0, tableView.rowHeight)] autorelease];

        [grid addColumn:60];

        label.tag = TAG_1; 
        label.font = [UIFont systemFontOfSize:14.0]; 
        label.text = dadosClientes.cod;
        label.textAlignment = UITextAlignmentRight; 
        label.textColor = [UIColor blackColor]; 
        label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight; 

        [grid.contentView addSubview:label]; 

        label =  [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 0, 20.0, tableView.rowHeight)] autorelease]; 

        [grid addColumn:100];

        label.tag = TAG_2; 
        label.font = [UIFont systemFontOfSize:14.0]; 
        label.text = dadosClientes.loja;
        label.textAlignment = UITextAlignmentCenter; 
        label.textColor = [UIColor blackColor]; 
        label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight; 

        [grid.contentView addSubview:label]; 

        label =  [[[UILabel alloc] initWithFrame:CGRectMake(110.0, 0, 350.0, tableView.rowHeight)] autorelease]; 

        [grid addColumn:470];

        label.tag = TAG_3; 
        label.font = [UIFont systemFontOfSize:14.0]; 
        label.text = dadosClientes.nome;
        label.textAlignment = UITextAlignmentLeft; 
        label.textColor = [UIColor blackColor]; 
        label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight; 

        [grid.contentView addSubview:label]; 

        label =  [[[UILabel alloc] initWithFrame:CGRectMake(480.0, 0, 240.0, tableView.rowHeight)] autorelease]; 

        [grid addColumn:730];

        label.tag = TAG_4; 
        label.font = [UIFont systemFontOfSize:14.0]; 
        label.text = dadosClientes.mun;
        label.textAlignment = UITextAlignmentLeft; 
        label.textColor = [UIColor blackColor]; 
        label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight; 

        [grid.contentView addSubview:label]; 

        label =  [[[UILabel alloc] initWithFrame:CGRectMake(740.0, 0, 20.0, tableView.rowHeight)] autorelease]; 

        [grid addColumn:768];

        label.tag = TAG_5; 
        label.font = [UIFont systemFontOfSize:14.0]; 
        label.text = dadosClientes.est;
        label.textAlignment = UITextAlignmentCenter; 
        label.textColor = [UIColor blackColor]; 
        label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight; 

        [grid.contentView addSubview:label]; 
    }

    UILabel *label_1 = (UILabel *)[grid.contentView viewWithTag:TAG_1];
    label_1.text = dadosClientes.cod;

    UILabel *label_2 = (UILabel *)[grid.contentView viewWithTag:TAG_2];
    label_2.text = dadosClientes.loja;

    UILabel *label_3 = (UILabel *)[grid.contentView viewWithTag:TAG_3];
    label_3.text = dadosClientes.nome;

    UILabel *label_4 = (UILabel *)[grid.contentView viewWithTag:TAG_4];
    label_4.text = dadosClientes.mun;

    UILabel *label_5 = (UILabel *)[grid.contentView viewWithTag:TAG_5];
    label_5.text = dadosClientes.est;

    return grid;
}

- (void) getInitialDataToDisplay:(NSString *)dbPath {

    count = [[NSMutableArray alloc] init];

    if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {

        const char *sql = "select cod, loja, nome, mun, est from apsa1010;";
        sqlite3_stmt *selectstmt;

        if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {

            while(sqlite3_step(selectstmt) == SQLITE_ROW) {

                iMapDadosClientes *dadosClientes = [[iMapDadosClientes alloc] cod:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 0)] loja:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)] nome:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)] pessoa:nil ender:nil bairro:nil mun:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 3)] est:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 4)] tel:nil bco1:nil risco:nil classe:nil lc:nil transp:nil ultCom:nil statCli:nil metr:nil salDup:nil uligTlv:nil dCompra:nil vend:nil celul:nil fax:nil email:nil contato:nil dtCada:nil priCom:nil dtNac:nil dtFunda:nil recno:nil];

                [count addObject:dadosClientes];

                [dadosClientes release];



                dadosClientes = nil;
            }
        }

        sqlite3_finalize(selectstmt);
    }
    else
        sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}

- (void) finalizeStatements {

    if(database)
        sqlite3_close(database);
}
有人在我的代码中给我一些我可能做错的提示。谢谢。

2 个答案:

答案 0 :(得分:0)

使用仪器检查由于保留但未泄漏的内存导致的泄漏和内存丢失。后者是未使用的内存,仍然指向。在仪器上的分配工具中使用快照。

如何使用“快照”查找内存褶皱,请参阅:bbum blog

基本上有一种方法是运行仪器分配工具,获取快照,运行代码直观和另一个快照重复3或4次。这将指示在迭代期间分配但未释放的内存。

要弄清楚披露的结果,以查看个别分配。

如果您需要查看对象使用仪器的保留,释放和自动释放的位置:

在仪器中运行,在分配中设置“记录参考计数”(您必须停止记录以设置选项)。导致选择器运行,停止记录,搜索那里的ivar(datePickerView),向下钻取,你将能够看到所有保留,释放和自动释放发生的位置。

答案 1 :(得分:0)

不确定这些是否是您的记忆问题,但这里有一些需要注意的事项。

始终检查所有sqlite调用的返回码。例如,sqlite3_finalize具有返回码,sqlite3_close也是如此。如果finalize不成功(例如,忙碌),您可能需要在关闭时进行清理(它不会为您执行此操作)。这是我的近距离功能:

if (_sqlite3)
{   
    int rc = sqlite3_close(_sqlite3);

    if (rc == SQLITE_BUSY) 
    {   
        sqlite3_stmt *stmt; 
        while ((stmt = sqlite3_next_stmt(_sqlite3, 0x00)) != 0) 
        {
            sqlite3_finalize(stmt); 
        }

        rc = sqlite3_close(_sqlite3);
    }

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

    _sqlite3 = NULL;
}

在内存问题之外,你应该看一下:

  • 准备编译sql语句可以给你一个引用(在你的情况下是& selectstmt)。你不应该每次都重新编译它。相反,在再次使用它之前,请先删除引用并调用sqlite3_reset,直到清理代码区域为止。这允许你在VBL中反复使用相同的编译语句 - 内存应保持稳定。

  • 为什么每次都要打开和关闭?这不是sql server客户端或具有连接池的东西。保持打开状态,重新使用已编译的语句,并从缓存和编译语句中受益。