释放变量但应用程序仍然泄漏内存并崩溃

时间:2011-05-09 11:21:14

标签: iphone xcode memory memory-management memory-leaks

当我的应用首次加载时,它会将来自多个文本文件的数据加载到SQLite数据库中。有很多数据,所以我将文件分割成几个较小的文件,然后使用下面的代码在循环中加载数据。我在每次传递时释放每个变量并写入NSLog以记录当时的内存状态。即使我发布变量,内存正在减少,我收到内存警告,1级& 2然后应用程序关闭。可能是因为向SQLite表添加数据会导致内存减少或者我的代码遗漏了什么?

while (filePathNo != @"7") {
  NSString *filePath;
  NSString *GenericName = nil; 
      .
      .
      // Nineteen Other Variables
      .
      .
  if (filePathNo == @"1") {
        filePath = [[NSBundle mainBundle] pathForResource:@"FileLoad1" ofType:@"txt"];
        filePathNo = @"2";
  }
      else if (filePathNo == @"2") {
        filePath = [[NSBundle mainBundle] pathForResource:@"FileLoad2" ofType:@"txt"];
        filePathNo = @"3";
  }
      .
      .
      // Five Other Files declared   
  .
      .

  NSString *textFromFile = [NSString stringWithContentsOfFile:filePath];

  NSString *cellString = textFromFile;
  NSRange range2 = [cellString rangeOfString:@"<string>"];
  range2 = [cellString rangeOfString:@"<string>"];
  if (range2.location != NSNotFound ) {
      eof = @"N";
      cellString = [cellString substringFromIndex:range2.location + 8];
  }

  while (eof != @"Y") {
    NSLog(@"Drug is - %@ , Memory free is  %d", GenericName, [self get_freemem]);
    progVal = progval + 1;                      
    [self performSelectorOnMainThread:@selector(updateMyProgressBar) withObject:nil waitUntilDone:NO];
    NSRange range1 = [cellString rangeOfString:@"#"];
    if (range1.location != NSNotFound )  
        GenericName = [cellString substringToIndex:range1.location]; 
    cellString = [cellString substringFromIndex:range1.location + 1];
            .
            .
            //  Find and load nineteen other variables
            .
            .
            range2 = [cellString rangeOfString:@"</string>"];
        if (range2.location != NSNotFound )            
        Doses = [cellString substringToIndex:range2.location];
    cellString = [cellString substringFromIndex:range2.location + 9];
    range2 = [cellString rangeOfString:@"<string>"];
    if (range2.location != 0 ) {
        eof = @"N";
        @try {
            cellString = [cellString substringFromIndex:range2.location + 8];
        }
        @catch (NSException *exception) {
            eof = @"Y";
        }
    }
    else {
        eof = @"Y";
    }
    if (cellString == nil) {
        eof = @"Y";
    }

    NSString *spkrs = @"";  
    char *errorMsg;
    char *update = "INSERT OR REPLACE INTO DRUGTABLE (FullDrugName, GenericName, OtherNames, TradeName, PrescriptionStatus, Formulations, DrugAction, DrugUse, SafetyAndHandling, Contraindications, AdverseReactions, DrugInteractions, Therapeuticgroup, GeneralAction, SpecificAction, ChemicalGroup, DrugReferences, Furtherreading, Doses) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
    //int errVal = sqlite3_prepare_v2(database, update, -1, &stmt, nil);
    if (sqlite3_prepare_v2(database, update, -1, &stmt, nil) == SQLITE_OK);
    {

        sqlite3_bind_text(stmt, 1, [FullDrugName  UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 2, [GenericName UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 3, [OtherNames UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 4, [TradeName UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 5, [PrescriptionStatus UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 6, [Formulations UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 7, [DrugAction UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 8, [DrugUse UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 9, [SafetyAndHandling UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 10, [Contraindications UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 11, [AdverseReactions UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 12, [DrugInteractions UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 13, [Therapeuticgroup UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 14, [GeneralAction UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 15, [SpecificAction UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 16, [ChemicalGroup UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 17, [References UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 18, [FurtherReading UTF8String], -1, NULL);
        sqlite3_bind_text(stmt, 19, [Doses UTF8String], -1, NULL);
    }
    if (sqlite3_step(stmt) != SQLITE_DONE)
    {
        NSString *err = errorMsg;
    }
    sqlite3_finalize(stmt);
    [spkrs release];
  } 
  [GenericName release]; 
  .
      .
      // Release all nineteen other variables
      .
      .
}

4 个答案:

答案 0 :(得分:1)

我认为你应该做的是将NSAutoReleasePool放在你的循环之外然后不时 drain它。您可能正在循环中创建自动释放对象,这些对象充当泄漏。例如。 cellString = [cellString substringFromIndex:range1.location + 1];

答案 1 :(得分:0)

除了上一个[spkrs release][GenericName release]之外,我在这段代码中看不到单个发布调用。

您是否尝试使用Xcode附带的分析器构建项目?它可以为您提供大量有用的信息,告知哪些对象泄漏,在哪里以及为什么。

尝试使用Run - &gt;从Performance Tool开始 - &gt;泄漏

答案 2 :(得分:0)

您不应该发布GenericStringspkrs,因为您永远不会allocretain。实际上,我不确定为什么你有一个spkrs变量,因为它看起来不像你用它做什么。

答案 3 :(得分:0)

尝试使用Instruments来跟踪分配在执行导入时的累积方式。我同意Anders K.关于利用自动释放池然后定期排水。

同意Berna先生的意见,创建数据库,然后将其添加到您的项目中,确保将其添加到您的Target和应用程序包中。

您可以调整一个很好的code in here代码段,演示如何在发布时为您的应用提供数据库。它在默认位置查找数据库,如果找不到,它将从您的包中复制它。