内存分配问题,设备 iOS SDK 4.1 崩溃(线程 0 崩溃)

Posted

技术标签:

【中文标题】内存分配问题,设备 iOS SDK 4.1 崩溃(线程 0 崩溃)【英文标题】:Memory alloc issues, crash on device iOS SDK 4.1(Thread 0 crash) 【发布时间】:2010-09-28 09:52:27 【问题描述】:

我有两个问题

1) 我的应用在前几次运行时在设备上运行良好。然后它在第一个屏幕弹出(Tab BAr)后崩溃。如果我将设备连接到我的 MAC,然后运行设备应用程序,它就可以工作(不是调试模式)。

我检查了崩溃日志,它崩溃了“EXC_BAD_ACCESS (SIGSEGV)”的 cos 并且 Thread0 崩溃了。错误是 NSAutorelease 释放了一个已释放的对象。

2) 我在模拟器上使用仪器运行应用程序。它在这个函数调用上显示了很多泄漏。 这是一个示例代码。当我使用 Instruments 运行它时,它会在“setObject”行显示泄漏。

//类A-NSObject的子类

+(NSMutableDictionary *)Hello 

 NSMutableDictionary *dctONE = [[NSMutableDictionary alloc]initWithCapacity:0];
 NSMutableArray *arrKeys = [[NSMutableArray alloc] initWithCapacity:0];

    [arrKeys addObject:@"Object1"];
 [arrKeys addObject:@"Object2"];

    [dctONE setObject:[NSString stringWithFormat:@"dsfsdf"] forKey:[arrKeys          objectAtIndex:0]];
 [dctONE setObject:[NSString stringWithFormat:@"dsfsdf"] forKey:[arrKeys objectAtIndex:1]];

    [arrKeys release];
    return dctONE;


/// B类

-(void)some_Function 
 NSMutableDictionary * dct = [A Hello];   //all declarations are done

 //do stuff with dct
 [dct release];

为什么它会在“setObject”处泄漏??我正在正确地释放一切,对吗?唯一的事情是 [NSString stringWithFormat:] 但那是自动释放对吗??

这让我发疯了吗?

这两个问题有关系吗?? PS:它不会在sim卡上崩溃,奇怪的是即使我将我的设备连接到我的MAC然后在设备上测试它也不会崩溃(不是调试,直接点击设备上的应用程序)

编辑:

-(NSMutableDictionary *) ExecuteDataSet:(NSString *)strQuery

    NSMutableDictionary  *dctResult = [[[NSMutableDictionary alloc] init] autorelease];
//  BOOL isSucess = FALSE;

const char *sql = [strQuery UTF8String];
sqlite3_stmt *selectStatement;

//prepare the select statement
int returnValue = sqlite3_prepare_v2(database, sql, -1, &selectStatement, NULL);
if(returnValue == SQLITE_OK)

    sqlite3_bind_text(selectStatement, 1, sql, -1, SQLITE_TRANSIENT);
    //loop all the rows returned by the query.
    NSMutableArray *arrColumns = [[NSMutableArray alloc] init];
    for (int i=0; i<sqlite3_column_count(selectStatement); i++) 
    
        const char *st = sqlite3_column_name(selectStatement, i);
        [arrColumns addObject:[NSString stringWithCString:st encoding:NSUTF8StringEncoding]];
    
    int intRow =1;
    while(sqlite3_step(selectStatement) == SQLITE_ROW)
    
        NSMutableDictionary *dctRow = [[NSMutableDictionary alloc] init];
        for (int i=0; i<sqlite3_column_count(selectStatement); i++)                 
        
            int intValue = 0;
            const char *strValue;
            switch (sqlite3_column_type(selectStatement,i)) 
            
                case SQLITE_INTEGER:
                    intValue  = (int)sqlite3_column_int(selectStatement, i);
                    [dctRow setObject:[NSString stringWithFormat:@"%d",intValue] forKey:[arrColumns objectAtIndex:i]];                      
                    break;

                case SQLITE_TEXT:
                    strValue = (const char *)sqlite3_column_text(selectStatement, i);
                    [dctRow setObject:[NSString stringWithCString:strValue encoding:NSUTF8StringEncoding] forKey:[arrColumns objectAtIndex:i]];                     
                    break;

                default:
                    strValue = (const char *)sqlite3_column_value(selectStatement, i);
                    [dctRow setObject:[NSString stringWithCString:strValue encoding:NSUTF8StringEncoding] forKey:[arrColumns objectAtIndex:i]];
                    break;
            

        
        [dctResult setObject:[dctRow retain] forKey:[NSString stringWithFormat:@"Table%d",intRow]];
        intRow ++;
        [dctRow release];
    
    [arrColumns release];

return dctResult;

【问题讨论】:

避免返回保留的对象,这是内存泄漏的大门。 但是我在进行调用的函数中释放了返回的对象。还不够好吗?如果没有,我如何返回分配的字典? 【参考方案1】:

泄漏似乎在这一行:

[dctResult setObject:[dctRow retain] forKey:[NSString stringWithFormat:@"Table%d",intRow]];

setObject 将在它存储的对象上调用retain,但您实际上是手动保留它,因此它的保留计数将是 2 而不是 1,并且当 dctResult 被释放时,它不会被删除凭记忆。

【讨论】:

好的,所以知道为什么“Leaks”说 [dctOne setObject:] 是“保留”并且我没有发布它。 另外,如果我通过“调用者”释放它,它不会错吧?还有对我的第一个问题的任何想法。设备崩溃?? 根据您的错误,您似乎是在自动释放池中的对象上手动调用release,然后,当池调用release 时,它会触发错误。您可以尝试启用 NSZombies 来追踪问题,并查看哪个已释放对象收到了消息。 @pgb 这就是问题所在,我已经广泛地检查了代码,并且我没有释放自动释放池中的任何变量。我唯一感到困惑的地方是“setObject”,因为我做了一个 [stringWithFormat:] 然后发布了字典,是因为这个错误吗? @pgb 我尝试使用 NSZombies,但结果很干净。没有检测到问题。 :(【参考方案2】:

你在+Hello 中做了一大堆不必要的工作。我调试的第一步总是消除不必要的复杂性。试试这样:

+(NSMutableDictionary *)Hello 

     NSMutableDictionary *dctONE = [NSMutableDictionary dictionaryWithObjectsAndKeys:
         @"dsfsdf", @"Object1", @"dsfsdf", @"Object2", nil];

     return dctONE;

NSMutableDictionary dictionaryWithObjectsAndKeys 方法采用一个以 nil 结尾的数组,该数组包含对象、键、对象、键。它返回一个自动释放的 NSMutableDictionary 对象,这是您想要返回的。

这个世界上没有任何保证,但我可以向你保证该方法不会泄漏。

【讨论】:

@Dan 感谢您的回复,但我在这里发布的 Hello 功能不是实际的。 [dctONE setObject:] 出现在一个 while 循环中,该循环正在从 sqlite DB 访问数据。泄漏显示在那条线上有泄漏,所以我只发布了一个简化版本。 @BK:好的,那么,从我对您的简化中收集到的内容。特别是使用返回自动释放对象的便利实例化器。 @Dan 我照你说的做了,并返回了一个自动释放的对象,但仍然没有运气。 “泄漏”指出 [setObject:] 是罪魁祸首。 当我不查看真实代码时,很难诊断这一点。你知道 [NSString stringWithFormat:@"abcd"] 是一个不必要的构造,对吧? 是的,我知道这一点。我用它来填充从 Db 返回的值的字典 -[stringWithFormat:@"%d",a];等待会放实际代码。

以上是关于内存分配问题,设备 iOS SDK 4.1 崩溃(线程 0 崩溃)的主要内容,如果未能解决你的问题,请参考以下文章

如何调试由于内存压力导致的 iOS 崩溃

iOS Facebook SDK 在 iOS 4.1 和 4.2 中崩溃

更新 google plus 和 facebook SDK 后应用程序在设备 (ios 6) 上崩溃

在 iOS 4.0 上释放 Autoreleasepool 崩溃(以及在 4.1 上......)

在 iOS 中通过 HTTP 获取图像时内存分配不断增加

使用 iOS 7 SDK 的随机 iOS 6 崩溃