开发者

Releasing variables but app still leaking memory and crashing

When my app loads for the first time, it loads data from several text files into a SQLite database. There is a lot of data so I have slit the file up into several smaller files and I load the data in a loop using the code below. I release each variable on each pass and write to NSLog to record the memory state at the time. Even though I am releasing the variables the memory is reducing and I receive memory warning, level 1 & 2 and then the app shuts down. Could it be that adding data to the SQLite table is causing the memory to reduce or have I missed something in my code?

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_pre开发者_开发百科pare_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
      .
      .
}


I think what you should do is to put a NSAutoReleasePool outside your loop and then now and then drain it. You are probably creating autorelease objects in your loop that are acting as a leak. E.g. cellString = [cellString substringFromIndex:range1.location + 1];


I cannot see a single release call in this piece of code apart of the last [spkrs release] and [GenericName release].

Did you try to build your project using the profiler that comes with Xcode? It can give you a lot of useful information of which objects are leaking, where and why.

Try it with Run -> Start with Performance Tool -> Leaks


You shouldn't be releasing GenericString or spkrs, since you never alloc or retain them. Actually, I'm not sure why you have a spkrs variable, since it doesn't look like you use it for anything.


Try to use Instruments to track how your allocations are accumulating while doing the import. I agree with Anders K. about utilizing the autorelease pool and then draining it periodically.

Also agree with Mr. Berna, create the database and then add it to your project, making sure that it is added to your Target and app bundle.

There is a good snippet of code in here that you can adapt that shows how to make the database available to your app at launch time. It looks for the database in the default location, if it can't find it, it will copy it from your bundle.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜