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

发布于 2024-11-06 02:24:59 字数 4654 浏览 1 评论 0原文

当我的应用程序第一次加载时,它会将多个文本文件中的数据加载到 SQLite 数据库中。有很多数据,因此我将文件分割成几个较小的文件,并使用下面的代码循环加载数据。我在每次传递时释放每个变量并写入 NSLog 以记录当时的内存状态。即使我正在释放变量,内存也会减少,并且我收到内存警告,级别 1 和级别 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
      .
      .
}

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_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
      .
      .
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蓬勃野心 2024-11-13 02:24:59

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

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];

酷遇一生 2024-11-13 02:24:59

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

您是否尝试使用 Xcode 附带的分析器来构建您的项目?它可以为您提供许多有用的信息,包括哪些对象正在泄漏、泄漏地点以及原因。

使用“运行”尝试一下 ->从性能工具开始 ->泄漏

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

哎呦我呸! 2024-11-13 02:24:59

您不应该释放 GenericStringspkrs,因为您永远不会allocretain 它们。实际上,我不确定为什么你有一个 spkrs 变量,因为它看起来不像你用它来做任何事情。

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.

变身佩奇 2024-11-13 02:24:59

尝试使用 Instruments 来跟踪导入时分配的累积情况。我同意 Anders K. 关于利用自动释放池然后定期耗尽它的观点。

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

有一个很好的片段 此处的代码,您可以对其进行调整,以显示如何在启动时使数据库可供您的应用程序使用。它会在默认位置查找数据库,如果找不到,则会从您的包中复制它。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文